LT一般默认模式
1 #include"wrap.h"
2 #include<errno.h>
3 #include<sys/epoll.h>
4 #define MAX_EVENT_NUM 1024
5 #define BUFF_SIZE 10
6
7 void delfd (int epollfd ,int fd)
8 {
9 struct epoll_event event;
10 event.events = EPOLLIN;
11 event.data.fd = fd;
12
13 epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&event);
14 }
15 void addfd(int epollfd , int fd)//fd做成结构体才能加入事件表
16 {
17 struct epoll_event event;
18 event.events = EPOLLIN;
19 event.data.fd = fd;
20
21 epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);
22 }
23 int main(int argc , char * argv[])
24 {
25 if(argc < 2 )
26 {
27 printf("输入IP和端口\neg:./a.out 127.0.0.2 8000\n");
28 exit(1);
29 }
30 const char * ip = argv[1];
31 int port = atoi(argv[2]);
32 struct sockaddr_in saddr,caddr;
33
34 int sfd = Socket(AF_INET,SOCK_STREAM,0);
35
36 bzero(&saddr,sizeof(saddr));
37 saddr.sin_family = AF_INET;
38 saddr.sin_port = htons(port);
39 inet_pton(AF_INET,ip ,&saddr.sin_addr.s_addr);
40 Bind(sfd,(struct sockaddr*)&saddr,sizeof(saddr));
41
42 Listen(sfd,5);
43
44 int epollfd = epoll_create(5);//创建epoll事件表的期望大小,返回事件表的根,即红黑树的根;
45 if(epollfd ==-1 )
46 perr_exit("epoll_crete error");
47
48 addfd(epollfd , sfd);//封装函数,将监听socket加入epoll事件表;
49
50 struct epoll_event events[MAX_EVENT_NUM];//定义就绪事件容器;
51 while(1)
52 {
53 int ret = epoll_wait(epollfd,events,MAX_EVENT_NUM,-1);
54 if(ret < 0)
55 perr_exit("epoll-wait error");
56 int i;
57 for(i=0; i < ret ; ++i)
58 {
59 if(!events[i].events & EPOLLIN)//只关注读事件
60 continue;
61
62 if(events[i].data.fd == sfd )//监听事件sfd分一类处理,接受客户端;
63 {
64 socklen_t len = sizeof(caddr);
65 int cfd = Accept(sfd,(struct sockaddr *)&caddr,&len);
66 char str[64];
67 printf("client cfd ip =%s port=%d\n",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,
68 str,64),ntohs(caddr.sin_port));
69 addfd(epollfd, cfd);//客户端放入监听事件表中epoll来监听;
70 }
71 else//其他客户端cfd事件分一类处理,读写数据
72 {
73 printf("event trigger once\n");
74 int sockfd = events[i].data.fd;//记录一下cfd方便使用;
75 char buff[BUFF_SIZE];
76 memset(buff,'\0',BUFF_SIZE);
77 int n = recv(sockfd,buff,BUFF_SIZE-1,0);
78 if(n == 0)//对方关闭
79 {
80 printf("client %d closing...\n",sockfd);
81 delfd(epollfd,sockfd);
82 continue;
83 }
84 if(n < 0)//接受数据出错
85 {
86 perror("client error");
87 delfd(epollfd,sockfd);
88 continue;
89 }
90 else//数据转化,并且发送数据
91 {
92 printf("get %d bytes content:%s\n",n,buff);
93
94 }
95 }
96
97 }
98 }
99
100
101 return 0;
102 }
客户端:fasdfddddddddddddddddddddddddddddddddd
服务器:
client cfd ip =127.0.0.1 port=33254
event trigger once
get 9 bytes content:fasdfdddd
event trigger once
get 9 bytes content:ddddddddd
event trigger once
get 9 bytes content:ddddddddd
event trigger once
get 9 bytes content:ddddddddd
event trigger once
get 3 bytes content:dd
结果:LT事件未读完事件触发多次去读
ET模式
客户端:fasdfddddddddddddddddddddddddddddddddd
服务器:
client cfd ip =127.0.0.1 port=33254
event trigger once
get 9 bytes content:fasdfdddd
get 9 bytes content:ddddddddd
get 9 bytes content:ddddddddd
get 9 bytes content:ddddddddd
get 3 bytes content:dd
结果:ET只是触发一次就能读完当前事件的内容;
Epoll的ET应用场景
在客户发送一大堆数据时,服务器只需要利用epollET的buff大小来读头部内容,来判断后面的大堆数据是否需要,不需要则可以直接丢弃,并且下一次event事件不会触发;LT模式即使头部读完不想要后面的数据,但LT模式下一次还会触发事件,因为没有读完的缘故;