2022年4月1日记:Linux服务器开发,网络io与select,poll,epoll
────────────────────────────────────
┌————————————┐
│▉▉♥♥♥♥♥♥♥♥ 99% │ ♥❤ 鱼沈雁杳天涯路,始信人间别离苦。
└————————————┘
对你的感情正在充电中,请稍侯…
────────────────────────────────────
推荐一个 零声学院 免费公开课程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习]
https://ke.qq.com/course/417774?flowToken=1042807
────────────────────────────────────
网络io与select,poll,epoll
- 三次握手发生在哪个api中?
- 单连接
- 总结
三次握手发生在哪个api中?
哪个都不是。
单连接
#define MAXLINE 4096void *client_rountine(void * arg){int connfd=*(int * )arg;char buff[MAXLINE];while(true){int n=recv(connfd,buff,MAXLINE,0);if(n>0){buff[n]='\0';printf("recv msg from client:%s\n",buff);}else if(n==0){close(connfd);break;}}return NULL;}int main(){while(true){struct sockaddr_in client;socklen_t len=sizeof(client);if((connfd=accept(listenfd,(struct sockaddr * )&client,&len)){printf("accept sockert error :"%s"(error:%d)\n",strerror(errno));return 0;}pthread_t threadid;pthread_create(threadod,NULL,client_rountine,(void *)&connfd); }}
一个线程退出,一个客户端退出,完全符合我们人的思维,但是似乎线程数不能太多。
阻塞点:
- accept();
- recv();
我们需要一个组件知道哪个fd上来数据了需要处理。
fd_set rfds,rset;FD_ZERO(rfds);FD_SET(listen,rfds);int max_fd=listenfd;while(true){rset=rfds;select(max_fd+1,&rset,NULL,NULL,NULL);}
- 一请求一线程,C10k。
- 多做select可以突破C10K。
select函数需要监控连接,copy到内核再copy出来性能也就随之下降,就会有局限。
epoll使用一组函数来完成任务,将关心的文件描述符上的事件放在内核里的一个事件表。
struct epoll_event{__uint32_t events;epoll_data_t data;};
总结
三组I/O复用函数的比较
select 的参数类型fd_set没有将文件描述符和事件绑定,它仅仅是一个文件描述符集合。换句话说,select不能处理更多类型的事件。另一方面,内核对fd_set集合的在线修改,应用程序下次调用select前不得不重置这三个fd_set集合。
poll更精明一些,它把文件描述符和事件定义其中,任何事件被统一处理。下次调用也无须重置pollfd类型的事件集参数。
epoll再内核维护一个时间表,并使用独立的epoll_ctl开控制其中的添加、删除、修改事件。epoll_wai调用都直接从该内核时间表中取得用户注册的事件,无须反复从用户空间读入这些事件。与前两者的索引就绪文件的时间复杂度从O(n),升级为了O(1),不错不错。虽然采用回调,而非轮询,但是当活动连接数比较多,epoll_wait()效率未必比前两者高。因此,epoll_wait适用于连接数量多,但是活动连接较少的情况。
只有epoll可以工作在高效的ET模式下。