Linux高性能服务器编程第七章Linux服务器程序规范

除了网络通信外,服务器程序还需要考虑其他细节问题,比如:

  • Linux服务器程序一般以后台进程形式进行,又称守护进程,没有控制终端,因而不会意外接收到用户输入,父进程通常为init进程
  • Linux服务器通常有一套日志系统,能输出日志到文件
  • Linux服务器程序一般以某个专门的非root身份运行,比如mysqld/httpd等后台进程,分别拥有自己的运行账户
  • Linux服务器程序通常可配置
  • Linux通常会启动时生成一个PID文件存入目录中,记录该后台进程的PID
  • Linux服务器程序通常要考虑系统资源和限制,预测自身能承受多大负荷

日志

用户信息

用户信息对于服务器程序的安全性来说是很重要的,比如大部分服务器就必须以root身份启动,但不能以root身份运行。下面这一组函数可以获取和设置当前进程的真实用户ID(UID)、有效用户ID (EUID)、真实组ID(GID)和有效组ID (EGID):

image-20231107160439460

进程间关系

进程组

Linux下每个进程都隶属于一个进程组,因此它们除了PID信息外,还有进程组ID(PGID)。我们可以用如下函数来获取指定进程的PGID:

1
2
#include <unistd.h>
pid_t getpgidi(pid_t pid);

服务器程序后台化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
bool daemonize (){
/*创建子进程,关闭父进程,这样可以使程序在后台运行*/
pid_t pid = fork ( ) ;
if ( pid < 0 )
return false;
else if (pid > 0){
exit(0);
}
umask(0);
//创建新会话,设置本进程为进程组首领
pid_t sid = setsid();
if(sid<0)
return false;
/*切换工作目录*/
if ((chdir("/")) < 0 )
return false;
/*关闭标准输入设备、标准输出设备和标准错误输出设备*/
close ( STDIN_FILENO );
close ( STDOUT_FILENO);
close ( STDERR_FILENO );
//关闭其他已经打开的文件描述符,代码省略
/*将标准输入、标准输出和标准错误输出都定向到/dev/null文件*/
open("/ dev/null",O_RDONLY);
open("/dev/null",O_RDWR);
open("/dev/null",O_RDWR);
return true;
}

linux也有自带的库函数:

1
2
#include<unistd.h>
int daemon(int nochdir,int noclose);

第一个参数指定是否改变工作目录,传递0则设置为根目录,否则使用当前工作目录

第二个参数为0,三个输出都重定向到/dev/null文件,否则还是使用原来的设备