Linux高性能服务器编程|阅读笔记:第7章 - Linux服务器程序规范
简介
Hello!
非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~
ଘ(੭ˊᵕˋ)੭
昵称:海轰
标签:程序猿|C++选手|学生
简介:因C语言结识编程,随后转入计算机专业,获得过国家奖学金,有幸在竞赛中拿过一些国奖、省奖…已保研
学习经验:扎实基础 + 多做笔记 + 多敲代码 + 多思考 + 学好英语!
唯有努力💪
本文仅记录自己感兴趣的内容
7.1 日志
7.1.1 Linux系统日志
linux提供一个守护进程来处理系统日志:rsyslogd
rsyslogd守护进程既能接收用户进程输出的日志,又能接收内核日志
用户进程是通过调用syslog函数生成系统日志的
该函数将日志输出道一个UNIX本地域socket类型的文件/dec/log中
rsyslogd则监听该文件以获取用户进程的输出
rsyslogd守护进程在接收到用户进程或内核输入的日志后,会把它们输出道某些特定的日志文件。
- 默认情况下,调试信息会保存在/var/log/debug
- 普通信息保存至/var/log/messages
- 内核消息保存至/var/log/kern.log
Linux系统日志体系:
7.1.2 syslog函数
应用程序使用syslog函数与rsyslogd守护进程通信
7.2 用户信息
7.2.1 UID、EUID、GID和EGID
大部分服务器必须要以root身份启动,但不能以root身份运行。
下面一组函数可以获取和设置当前进程的真实用户ID(UID)、有效用户ID(EUID)、真实组(GID)、有效组(EGID)
一个进程拥有两个用户ID:UID和EUID
- EUID存在的目标:方便资源访问,
使得运行程序的用户拥有该程序的有效用户权限
简单理解:比如su程序,su程序的有效用户权限是root,但是普通用户也可以在运行su程序时,拥有su程序的有效用户权限,也就是root(仅限于此程序)
小实验:测试进程的UID和EUID的区别
#include <unistd.h>
#include <stdio.h>
int main()
{
uid_t uid = getuid();
uid_t euid = geteuid();
printf( "userid is %d, effective userid is: %d\n", uid, euid );
return 0;
}
7.2.2 切换用户
以root身份启动的进程切换为以一个普通用户身份运行:
static bool switch_to_user( uid_t user_id, gid_t gp_id )
{
// 先确保目标用户不是root
if ( ( user_id == 0 ) && ( gp_id == 0 ) )
{
return false;
}
// 确保当前用户是合法用户:root或目标用户
gid_t gid = getgid();
uid_t uid = getuid();
if ( ( ( gid != 0 ) || ( uid != 0 ) ) && ( ( gid != gp_id ) || ( uid != user_id ) ) )
{
return false;
}
// 如果不是root 则已经是目标用户
if ( uid != 0 )
{
return true;
}
// 切换到目标用户
if ( ( setgid( gp_id ) < 0 ) || ( setuid( user_id ) < 0 ) )
{
return false;
}
return true;
}
7.3 进程间关系
7.3.1 进程组
Linux下每个进程都隶属于一个进程组,因此它们除了PID信息外,还有进程组ID(PGID)
获取指定进程的PGID
设置PGID
每个进程组都有一个首领进程,其PGID和PID相同。
进程组将一直存在,直到其中所有进程都退出或者加入其他进程组
7.3.2 会话
一些有关联的进程组
将形成一个会话(session)
创建一个会话:
此函数不能由进程组的首领进程调用,否则会产生一个错误
7.3.3 用ps命令查看进程关系
7.4 系统资源限制
Liux上运行的程序都会受到资源限制的影响,比如物理设备限制(CPU数量、内存数量等)、系统策略限制(CPU时间等),以及具体实现的限制(比如文件名的最大长度)。
7.5 改变工作目录和根目录
有些服务器程序还需要改变工作目录和根目录
一般来说,Web服务器的逻辑根目录并非文件系统的根目录“/”,而是站点的根目录(对于
Linux的Web服务来说,该目录一般是var/www/)
获取进程当前工作目录和改变进程工作目录的函数分别是:
7.6 服务器程序后台化
将服务器程序以守护进程的方式运行:
bool daemonize()
{
// 创建子进程,关闭父进程,这样可以使得程序在后台运行
pid_t pid = fork();
if ( pid < 0 )
{
return false;
}
else if ( pid > 0 )
{
exit( 0 );
}
// 设置文件权限掩码
// 当进程创建新文件 使用open等系统调用时,文件的权限将是 mode & 0777
umask( 0 );
// 创建新的会话,设置本进程为进程组的首领
pid_t sid = setsid();
if ( sid < 0 )
{
return false;
}
// 切换工作目录
if ( ( chdir( "/" ) ) < 0 )
{
/* Log the failure */
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;
}
结语
文章仅作为个人学习笔记记录,记录从0到1的一个过程
希望对您有一点点帮助,如有错误欢迎小伙伴指正
- 点赞
- 收藏
- 关注作者
评论(0)