采用Nginx的源码思想来写
监听套接字队列
监听端口数有多少个,那么监听队列就多长
结构体ngx_listening_s 每一个都包含
- 端口号
- sockfd
- 指向连接对象的指针
vector<ngx_listening_s> 对象数组,刚开始在运行前就被初始化,配置好
连接池
可以看成 对象数组
每一个对象是一个结构体,包含
- 监听套接字对象指针
- 序号 iCurrsequence ,每一次分配时候都+1
- 失效标志位instance ,初始为1,即失效; unsigned instance:1 // :1代表只占一位
- 指向对象的指针,维护一条空闲连接链表,lpngx_connection_t指针永远指向链表头。
- 成员函数指针
CSocekt类的成员函数指针,参数(连接对象指针)指向读操作时候调用的函数
当需要时候,直接返回链表头节点,高效。
过程调用
-
监听对象队列在运行前就初始化,监听端口,
-
在子进程不断循环的过程中,调用epoll_init()初始化,
-
调用epoll_create()函数生成epoll对象(文件描述符)
int epoll = epoll_create(int size);
每一个进程都调用该函数,那么每一个进程都生成epoll对象、都有连接池,每一个进程的连接池都和监听套接字队列进行关联(这就是SO_REUSEADDR的作用) -
初始化连接对象链表,遍历监听套接字队列,将监听对象和连接对象互相关联。
-
监听对象增加监听事件,关注读事件和关闭事件。
在子进程不断地调用ngx_epoll_process_events()函数
epoll_wait()函数返回捕获事件个数,遍历捕获的事件个数,判断事件类型,若是读事件,则执行回调函数
回调函数ngx_event_accept()是在接收到三次握手后,建立新连接
accpet(监听sockfd,sock地址,socklen)
或accpet4(监听sockfd,sockaddr地址,sockaddr地址长度,设置非阻塞)
用accept()返回的新的客户端sockfd取出连接数组里的对象
用连接对象调用读取函数,将读事件写入监控。