概述
除了网络通信外,服务器程序还必须考虑许多其他细节问题,零碎,但基本上是模板式的。比如:
- Linux服务器程序一般以后台形式运行。后台程序又称守护进程。它没有控制终端,因而也不会意外接受用户输入。守护进程的父进程一般是init进程(PID=1)
- Linux服务器程序通常有一套日志系统,它至少能输出日志到文件,有的高级服务器可以输出日志到专门的UDP服务器。大部分后台进程都在/var/log下有自己的日志目录
- Linux服务器程序一般以某个专门的非root身份运行。mysqld, httpd, syslogd等后台进程,并分别有自己的运行账户mysql, apache, syslog
- Linux服务器通常时可配置的。服务器程序通常处理很多命令选项,如果一次运行的选项太多,则克拉一用配置文件来管理。绝大多数服务器程序都有配置文件并存放在/etc下
- Linux服务器程序通常在启动时生成一个PID文件并存入/var/run目录中,以记录该后台进程的PID。
- Linux服务器程序通常需要考虑系统资源和限制,以预测自身能承受多大负荷,比如进程可用文件描述符总数和内存总量等
日志
Linux系统日志
用户日志函数 syslog:生成系统日志,输出到一个UNIX本地域socket类型(AF_UNIX)的文件/dev/log中
守护进程 rsyslogd:接收用户进程输出的日志,又能接收内核日志,监听上述文件以获取用户进程的输出
内核日志函数 printk:打印至内核的环状缓存中,环状缓存的内容直接映射到/proc/kmsg文件中。rsyslogd则通过读取该文件获得内核日志
默认情况下,调试信息保存在/var/log/debug,普通信息保存至/var/log/messages,内核信息:/var/log/kern.log
rsyslogd 主配置文件是/etc/rsyslog.conf,主要设置的项包括:内核日志输入路径,是否接受UDP日志,及其监听端口(默认514 /etc/services),是否接受TCP日志及其监听端口,日志文件权限,包含哪些子配置文件
syslog函数
1.作用
与rsyslogd守护进程通信
2.定义
#include <syslog.h>
void syslog ( int priority, const char* message, ... ); // 可变参数
3.函数说明
第二个和第三个参数为可变参数,为了结构化输出
priority参数:设施值与日志级别的按位或。设施值的默认值是LOG_USER,可选值如下:
#include <syslog.h>
#define LOG_EMERG 0 /* 系统不可用 */
#define LOG_ALERT 1 /* 报警,需要立即采取动作 */
#define LOG_CRIT 2 /* 非常严重的情况 */
#define LOG_ERR 3 /* 错误 */
#define LOG_WARNING 4 /* 警告 */
#define LOG_NOTICE 5 /* 通知 */
#define LOG_INFO 6 /* 信息 */
#define LOG_DEBUG 7 /* 调试 */
4.函数openlog
- 作用:改变syslog的默认输出方式,进一步结构化日志内容
- 声明
#include <syslog.h>
void openlog ( const char* ident, int logopt, int facility );
- 函数说明
ident:指定的字符串将被添加到日志消息的日期和时间之后,通常被设置为程序的名字。
logopt:对后续syslog调用的行为进行配置,可取下列值的按位或:
#define LOG_PID 0x01 /* 在日志消息中包含程序PID */
#define LOG_CONS 0x02 /* 如果消息不能记录到日志文件,则打印至终端 */
#define LOG_ODELAY 0x04 /* 延迟打开日志功能直到第一次调用syslog */
#define LOG_NDELAY 0x08 /* 不延迟打开日志功能 */
facility:修改syslog函数中的默认设施值
函数setlogmask
- 作用:使日志级别大于日志掩码的日志信息被系统忽略
- 函数声明
#include <syslog.h>
int setlogmask( int maskpri );
- 函数说明:
maskpri:指定日志掩码值。
该函数始终会成功,返回调用进程先前的日志掩码值。 - 举例
setlogmask(LOG_ERR); //仅仅记录ERR级别的日志消息
setlogmask(LOG_UPTO(LOG_ERR)); //记录ERR以及之前的所有日志的消息[0,3] - 关闭日志功能:
#include <syslog.h>
void closelog();
用户信息
1. UID, EUID, GID, EGID
Tables | Are | get / set |
---|---|---|
UID | 真实用户ID | getuid() / setuid(uid_t uid) |
EUID | 有效用户ID | geteuid() / setuid(uid_t uid) |
GID | 真实组ID | getgid() / setuid(gid_t gid) |
EGID | 有效组ID | getgeid() / setuid(gid_t gid) |
一个进程拥有两个用户ID,UID,EUID。EUID存在的目的是为了方便资源的访问, 它使得运行程序的用户拥有该程序的有效用户权限
2. 切换用户
以root身份启动的进程切换为以一个普通用户身份运行
static bool switch_to_user(uid_t user_id, gid_t gp_id)
{
if((user_id == 0) && (gp_id == 0))
return false;
gid_t gid = getgid();
uid_t uid = getuid();
if( ( (gid != 0) || (uid!= 0)) && (( gid != gp_id) || ( uid != user_id )) )
return false;
if(uid != 0)
return false;
if((setgid(gp_id) < 0) || setuid(user_id) < 0))
return false;
return true;
}
进程间关系
(未完待续…)