epoll服务器
来源:互联网 发布:excel学生成绩管理数据 编辑:程序博客网 时间:2024/05/21 09:45
下面来看看linux内核具体的epoll机制实现思路。
当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体,这个结构体中有两个成员与epoll的使用方式密切相关。eventpoll结构体如下所示:
每一个epoll对象都有一个独立的eventpoll结构体,用于存放通过epoll_ctl方法向epoll对象中添加进来的事件。这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是lgn,其中n为树的高度)。
而所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当相应的事件发生时会调用这个回调方法。这个回调方法在内核中叫ep_poll_callback,它会将发生的事件添加到rdlist双链表中。
在epoll中,对于每一个事件,都会建立一个epitem结构体,如下所示:
当调用epoll_wait检查是否有事件发生时,只需要检查eventpoll对象中的rdlist双链表中是否有epitem元素即可。如果rdlist不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户。
epoll数据结构示意图
从上面的讲解可知:通过红黑树和双链表数据结构,并结合回调机制,造就了epoll的高效。
OK,讲解完了Epoll的机理,我们便能很容易掌握epoll的用法了。一句话描述就是:三步曲。
第一步:epoll_create()系统调用。此调用返回一个句柄,之后所有的使用都依靠这个句柄来标识。
第二步:epoll_ctl()系统调用。通过此调用向epoll对象中添加、删除、修改感兴趣的事件,返回0标识成功,返回-1表示失败。
第三部:epoll_wait()系统调用。通过此调用收集收集在epoll监控中已经发生的事件。
epoll优点:
1.epoll维护的描述符数目不受到限制,而且性能不会随着描述符数目的增加而下降。(不需要遍历整个文件描述符)
2.epoll先通过epoll_ctl注册一个描述符到内核中,并一直维护着而不像poll每次操作都将所有要监控的描述符传递给内核
3.在描述符读写就绪时,通过回掉函数将自己加入就绪队列中,之后epoll_wait返回该就绪队列,所以用户不需要遍历整个文件描述符判断哪些事件就绪。性能提升。
4.支持ET高效模式。
void usage(const char* str )
12 {
13 printf("usage:[local_IP][local_port]\n",str);
14 }
15
16 int startup(const char* ip,int port)
17 {
18 int listen_sock=socket(AF_INET,SOCK_STREAM,0);
19 if(listen<0){
20 perror("sock");
21 exit(2);
22 }
23 struct sockaddr_in local;
24 local.sin_family=AF_INET;
25 local.sin_port=htons(port);
26 local.sin_addr.s_addr=inet_addr(ip);
27 if(bind(listen_sock,(struct sockaddr *)&local,sizeof(local))<0){
28 perror("bind");
29 exit(3);
30 }
31 if(listen(listen_sock,20)<0){
32 perror("listen");
33 exit(4);
34 }
35 return listen_sock;
36 }
37 int main(int argc,char* argv[])
39 {
40 if(argc!=3){
41 usage(argv[0]);
42 exit(1);
43 }
44 int listen_sock=startup(argv[1],atoi(argv[2]));
45
46 int epollfd=epoll_create(256);
47 if(epollfd<0){
48 perror("epoll");
49 close(listen_sock);
50 exit(5);
51 }
52
53 struct epoll_event ev;
54 ev.events=EPOLLIN;
55
56 int ret=epoll_ctl(epollfd,EPOLL_CTL_ADD,listen_sock,&ev);
57
58 struct epoll_event evs[64];
59 int timeout=1000;
60 int nums=0;
61
62 while(1){
63 switch(nums=epoll_wait(epollfd,evs,64,timeout)){
64 case 0:
64 printf("timeout..\n");
65 break;
66 case -1:
67 perror("epollwait");
68 break;
69 default:{
70 int i=0;
71 for(;i<64;i++){
72 int sock=evs[i].data.fd;
73 if(sock==listen_sock&&(evs[i].events&EPOLLIN)){
74 //listen_sock ready;
75 struct sockaddr_in client;
76 socklen_t len=sizeof(client);
77 int new_sock=accept(listen_sock,(struct sockaddr*)&client,&len);
78 if(new_sock<0){
79 perror("acceot");
80 continue;
81 }
82 ev.events=EPOLLIN;
83 ev.data.fd=new_sock;
84 epoll_ctl(epollfd,EPOLL_CTL_ADD,new_sock,&evs);
85 85
86
87 }else if(sock!=listen_sock){
88 if(evs[i].events&EPOLLIN){
89 //normal ready;
90 char buf[1024];
91 ssize_t s=read(sock,buf,sizeof(buf)-1);
92 if(s>0){
93 printf("client say# :%s\n",buf);
94 ev.events=EPOLLOUT;
95 ev.data.fd=sock;
96 epoll_ctl(epollfd,EPOLL_CTL_MOD,sock,&evs);
97 }else if(s==0){
98 printf("client quit\n");
99 epoll_ctl(epollfd,EPOLL_CTL_DEL,sock,NULL);
100 }else {
101 perror("read");
102 close(sock);
103 epoll_ctl(epollfd,EPOLL_CTL_MOD,sock,&ev);
104 }
105 }
106 }else {
107 if(evs[i].events&EPOLLOUT){
108 //normal wrute ready
109 const char *msg = "HTTP/1.0 200 OK\r\n\r\n<html><h1> hello epoll!</h1></html>";
110 write(sock,msg,strlen(msg));
111 }
112 }
112,6-24 83%
- epoll服务器
- epoll服务器
- epoll服务器
- epoll服务器
- Epoll服务器
- epoll服务器
- epoll服务器
- linux服务器编程--EPOLL
- epoll服务器示例
- 并发服务器之epoll
- epoll服务器编程-demo
- epoll服务器开发详解
- epoll回显服务器
- Epoll服务器架构
- 服务器epoll初用
- linux下epoll服务器
- python epoll开发服务器
- Epoll模型服务器实现
- WiFi-ESP8266入门开发(二)-连接WiFi网络
- Spring基础(2)
- oracle pl/sql脚本常用技巧
- MyEclipse中如何去掉JS/JSP语法错误提示
- 归并排序
- epoll服务器
- axi学习总结
- 简单++--运算符
- PHP基础入门(四)---PHP数组实用基础知识
- Spring基础(3)
- jQuery全屏banner焦点图切换
- 混淆网络和词格或者字格
- Codeforces Round #422 D. My pretty girl Noora (数论)
- 2.2 Git Basics