Linux高性能服务器编程-游双——第七章 Linux服务器程序规范

  • 除了网络通信,服务器通常还需要考虑其他问题。
  • Linux服务器程序通常以后台进程形式运行,后台进程又称为守护进程。
  • Linux服务器程序通常有一套日志系统,它至少能输出日志到文件。
  • Linux服务器程序一般以某个专门的非root身份运行,拥有自己的运行账户。
  • Linux服务器陈鼓型通常是可以配置的,服务器程序通常能处理很多命令行选项,如果选项太多,可以用配置文件来管理。
  • Linux服务器经常在启动时候生成一个PID文件并存入/var/run目录中,以记录该后台进程的PID
  • LInux服务器程序通常需要考虑系统资源和限制。

7.1 日志

7.1.1 Linux系统日志

  • Linux提供一个守护进程来 处理系统日志——rsyslogd
  • rsyslogd守护进程收到用户进程或内核输入日之后,会将其输出到某些特定的日志文案金,默认情况下调试信息会保存到/var/log/debug,普通信息保存到/var/log/message,内核信息保存到/var/log/kern.log
  • 在这里插入图片描述

7.1.2 syslog函数

  • 应用程序使用syslog函数和守护进程rsyslog通信
#include <syslog.h>
void syslog(int priority, const char* message, ...);
  • priority是设置值(默认为LOG_USER)与日志级别的按位或,
    日志级别:
    在这里插入图片描述
  • 函数openlog用来改变syslog的默认输出方式,进一步结构化日志内容
#include <syslog.h>
void openlog(const char* ident, int logopt, int facility);
  • ident参数指定的字符串将被添加到日志信息的日期和时间之后,通常被设置为程序俄名字。

  • logopt参数对后续syslog调用的行为进行配置,它可以取下列值得按位或:
    在这里插入图片描述

  • facility参数修改syslog函数中的默认设施值。

  • 设置日志掩码,使得日志级别大于日志掩码的信息被系统忽略。

#include <syslog.h>
int setlogmask(int maskpri);
  • maskpri参数指定日志掩码值,该函数始终会成功,它返回调用进程先前的日志掩码值
  • 关闭日志功能
#include <syslog.h>
void closelog();

7.2 用户信息

  • 部分服务器必须以root身份启动,但是不能以root身份运行。
  • 下边一组函数可以获取和设置当前进程的UID、EUID、GID、EGID
#include <sys/types.h>
#include <unistd.h>
uid_t getuid();		//获取真实用户ID
uid_t geteuid();	//获取有效用户ID
gid_t getgid();		//获取真实组ID
gid_t getegid();	//获取有效组ID

int setuid(uid_t uid);		//设置真实用户ID
int seteuid(uid_t uid);		//设置有效用户ID
int setgid(gid_t gid);		//设置真实组ID
int setegid(gid_t gid);		//设置有效组ID
  • 一个进程同时拥有UID和EUID两个用户ID,EUID的目的是方便资源访问,它使得运行程序的用户拥有该程序的有效用户的权限。
  • 也就是说,就算是普通用户运行su程序,由于su程序的所有者是root,所以su程序的EUID就是root用户。
  • 例如:
#include <unistd.h>
#include <stdio.h>

int main(){
    uid_t uid = getuid();
    uid_t euid = geteuid();
    printf("userid :%d , euid: %d \n", uid, euid);
    return 0;
}

设置程序的所有者,以及set-user-id标志

$ sudo chown root:root uid_euid_test
$ sudo chmod +s uid_euid_test
  • 设置+s标志的作用是s:当文件被执行时,根据who参数指定的用户类型设置文件的setuid或者setgid权限。
  • 设置完成,输出为:
userid :1000 , euid: 0 

运行程序的用户是1000,有效用户是0,也就是root用户。

7.2.2 切换用户

  • 下边的例子展示了以root用户启动的进程切换为一个普通用户身份运行。

7.3 进程间关系

7.3.1 进程组

  • Linux下的每一个进程都隶属于一个进程组,因此他们处理PID信息外,还有进程组ID,PGID。
  • 获取和设置进程组id
#include <unistd.h>
//获取进程pid的进程组pgid,失败返回-1。
pid_t getpgid(pid_t pid);
//把PID为pid的进程的PGID设置为pgid
int setpgid(pid_t pid, pid_t pgid);
  • 如果pid和pgid相同,则pid指定的进程将被设置为进程组的首领,如果pid为0,则表示设置当前进程的PGID为pgid。
  • 进程只能设置自己和子进程的PGID,当子进程调用exec系列函数后,不能在父进程对齐设置PGID

7.3.2 会话

  • 有关联的进程组将形成一个会话。
  • 创建会话:
#include <unistd.h>
pid_t setsid(void);
  • 注意,该函数不能由进程组首领调用,否则会出错。对于非首领进程来说,调用该函数会生成一个新的会话,并且
    • 调用进程会称为会话新首领,此时进程是会话的唯一成员
    • 新建一个进程组,PGID就是调用该函数的进程PID,调用进程成为首领
    • 调用进程甩开终端(若有)。
  • Linux并没有提供会话ID的概念,他认为会话ID等同于会话首领所在进程的PGID
#include <unistd.h>
pid_t getsid(pid_t pid);
  • 获取会话ID

7.3.3 用ps命令查看进程关系

$ ps -o pid,ppid,pgid,sid,comm | less
  PID   PPID   PGID    SID COMMAND
  9842   9837   9842   9842 bash
 12675   9842  12675   9842 ps
 12676   9842  12675   9842 less

7.4 系统资源限制

  • Linux上运行的程序会受到资源限制的影响。
    • 物理设备限制:CPU数量,内存数量
    • 系统策略限制:CPU时间
    • 具体实现限制:文件名的最大长度。
  • 读取和设置系统资源限制
#include <sys/resource.h>
//成功返回0,失败返回-1并设置errno
int getrlimit(int resurce, struct rlimit *rlim);
int setrlimit(int resurce, const struct rlimit *rlim);

struct rlimit {
	//rlim_t 描述资源级别
	rlim_t rlim_ur;		//软限制
	rlim_t rlim_max;	//硬限制
}
  • resource参数指定资源限制类型
    在这里插入图片描述

7.5 改变工作目录和根目录

  • 有一些服务器还需要改变工作目录和根目录
  • 一般来说,web服务器的逻辑根目录不是文件系统的根目录,而是站点的根目录。
  • 获取进程当前工作目录,改变进程工作目录
#include <unistd.h>
char* getcwd(char* buf, size_t size);
int chdir(const char* path);
+ getcwd把当前工作目录存储在buf中,如果目录太大,超过size,则会返回NULL,获取失败。
+ 如果getcwd的参数buf指向NULL,且size非0,则getcwd可能会使用malloc申请空间,这时候我们要手动释放空间。
+ getcwd成功时候返回buf指向的缓存区的地址。
+ chdir成功返回0,失败返回-1。
  • 改变进程根目录chroot
#include <unistd.h>
//成功返回0,失败返回-1并设置errno
int chroot(const char* path);
  • chroot之后,进程原先打开的文件描述符仍然生效。

7.6 服务器程序后台化

  • 创建子进程,关闭父进程,这样子进程的程序就可以在后台运行。
  • Linux提供了可以将服务器程序后台化的库函数。
#include <unistd.h>
//成功返回0,失败返回-1并设置errno。
int daemon(int nochdir, int noclose);
  • nochdir参数用于指定是否改变工作目录,如果传递0,则工作目录将使用“/”,也就是根目录。
  • noclose参数为0时候,标准输入,标准输出,标准错误都将被重新定义到/dev/null文件,否则将使用原来的设备。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值