Linux的服务器软件,大多是基于epoll事件机制的多进程架构。
其中有一个主进程master,负责监控其他进程的状态。如果其他进程异常退出,则把它从新启动起来。
其他的进程是工作进程worker,负责具体的业务处理。
worker进程的主函数是一个基于epoll事件机制的循环,监控它负责的socket连接的读写状态,读取数据并且调用相关的各个协议解析模块进行处理,应答用户的请求。
之所以用多进程结构,是个别worker进程的异常退出不会导致整个服务器程序的退出,而是会被master进程再次启动起来继续服务,比多线程的稳定性要高。
带来的问题之一就是,跨进程的数据通信比较繁琐。一般是关键信息通过AF_UNIX域的socketpair传递,如果是视频之类的大量数据则使用共享内存。
典型的Linux高并发服务器,就是著名的nginx,作者俄罗斯程序员Igor Syseov。
1,主进程master,
主进程在初始化结束之后的工作比较简单,主要是监控工作进程的状态,并及时重启异常退出的工作进程。
再就是接受用户的命令,例如reload,quit之类的操作。
Linux的子进程退出时会给父进程发送SIGCHILD信号,然后父进程可以使用wait系统调用获取子进程的退出状态。
信号的传递是异步的,需要用Linux的signal()函数挂载自定义的信号处理函数,然后就可以捕获子进程的SIGCHILD信号了。
主进程master发现子进程worker退出后,就可以用fork()系统调用再创建一个子进程,以维持worker进程的个数。
其他时间master只需要关注标准输入STDIN,及时获取用户的命令。
2,worker进程,
worker进程的主循环是一个死循环,不断的用epoll_wait()系统调用监控socket连接的状态。
如果有数据可读,则读取数据,并调用相关的模块进行处理。
如果有新连接要接入,则使用accept()函数获取连接的文件描述符,并为该用户创建连接的上下文,该上下文代表服务器上的一个用户。
同时这个主循环还要处理定时器问题,有时候给用户发送的数据需要控制带宽,就按定时器每多少毫秒发送多少字节,以保证带宽不会暴涨暴跌。
定时器需要频繁的添加、删除、查找,所以多是使用红黑树作为管理结构。
定时器的精度取决于epoll_wait的超时时间。
下图为Linux man手册关于epoll_wait的介绍,它的最后一个参数就是超时的毫秒数。
即使没有等到新数据到达,在超时之后也会返回,这时可以处理定时器。极端情况下,定时器的最粗精度取决于这个超时的时间。
工作进程的主循环代码大概这样:
while(!exit) { //如果没有退出标志则循环
int ret = epoll_wait(epfd, events, max events, timeout);
if (ret < 0) {
//出错处理
break;
}
//正常返回时的ret返回值是触发的事件个数
int i;
for (i =0; i < ret; i ++) {
//遍历处理所有的触发事件
}
//处理到时间的定时器事件
}
像http之类的具体协议的处理,都是在事件的回调函数里做的。
epoll_event的结构分两个部分,一个是具体的epoll事件的标志,例如EPOLLIN表示读,EPOLLOUT表示写。
另一部分是用户自定义的上下文数据的指针。各模块的数据结构可以放在这个指针里。
如下图,可以把自定义数据结构挂在e->data.ptr里,其中e为struct epoll_event类型的指针。
假设自定义的连接上下文结构是:
struct connection {
int fd; // socket文件描述符
int (*read)(struct connnection* c);
//读数据的函数指针
int (*write)(struct connection* c);
//写数据的函数指针
uint8_t* readbuf; //读缓冲区
int readbuf_size; //当前读缓冲区大小
uint8_t* writebuf; //写缓冲区
int writebuf_size; //写缓冲区大小
void* data; //下一级模块的结构体
};
那么工作进程worker的主循环while()里,遍历触发的事件的for循环的处理就是:
for (i =0; i < ret; i++) {
struct epoll_event* e = &events[i];
struct connection * c = e->data.ptr;
int ret2 = c->read(c);
...
}
这只是示例代码,nginx的这部分代码还是比较复杂的。
最精简的事件框架记得是redis自带的libae,大概几百行。
libevent框架则特别的复杂。
举报/反馈