LT:在数据到达之后,无论程序是没有接收,还是接收了,但没有接收完,下一轮epoll_wait仍然会提醒应用程序该描述符上有数据,知道数据被接收完。
ET:在数据到达之后,无论程序是没有接收,还是接收了,但是没有接收完,都只提醒一次,下一轮不再提醒应用程序该描述符上有数据。
同一事件仅仅被触发一次
ET的实现:
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/epoll.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<errno.h>
#include<fcntl.h>
#define SIZE 100
void SetNonBlock(int fd)//将文件描述符设置成非阻塞的
{
int old=fcntl(fd,F_GETFL);
int new=old | O_NONBLOCK;
fcntl(fd,F_SETFL,new);//将new设置到fd上
}
int Create_Socket()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in ser;
memset(&ser,0,sizeof(ser));
ser.sin_family=AF_INET;
ser.sin_port=htons(6000);
ser.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr*)&ser,sizeof(ser));
assert(res!=-1);
listen(sockfd,5);
return sockfd;
}
void et(int fd,struct epoll_event event,int epollfd)
{
if(event.events&EPOLLRDHUP)
{
close(fd);
epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,NULL);
printf("%d client break link;\n",fd);
}
else if(event.events&EPOLLIN)
{
printf("%d S data is:\n", fd);
while(1)
{
char buff[128]={0};
int n=recv(fd,buff,5,0);
if(n<=0)
{
if(errno==EAGAIN || errno==EWOULDBLOCK)
{
break;
}
close(fd);
epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,NULL);
}
printf("%s",buff);
}
printf("\n");
send(fd,"OK",2,0);
}
else
{
printf("error\n");
}
}
void Deal_Link(struct epoll_event events[],int n,int sockfd,int epollfd)
{
int i=0;
for(;i<n;++i)
{
int fd=events[i].data.fd;
if(fd==sockfd)
{
struct sockaddr_in cli;
int len=sizeof(cli);
int c=accept(fd,(struct sockaddr*)&cli,&len);
if(c<0)
{
printf("One client link error\n");
continue;
}
SetNonBlock(c);
struct epoll_event event;
event.events=EPOLLIN | EPOLLRDHUP | EPOLLET;
event.data.fd=c;
epoll_ctl(epollfd,EPOLL_CTL_ADD,c,&event);
}
else
{
et(fd,events[i],epollfd);
}
}
}
int main()
{
int sockfd=Create_Socket();
int epollfd=epoll_create(5);
assert(epollfd!=-1);
struct epoll_event event;
event.events=EPOLLIN;
event.data.fd=sockfd;
epoll_ctl(epollfd,EPOLL_CTL_ADD,sockfd,&event);
while(1)
{
struct epoll_event events[SIZE];
int n=epoll_wait(epollfd,events,SIZE,-1);
if(n<=0)
{
printf("epoll wait error\n");
continue;
}
printf("epoll wait return\n");
Deal_Link(events,n,sockfd,epollfd);
}
}
注意:
- 文件描述符必须设置为非阻塞模式
- 内核事件表上的文件描述符必须关注EPOLLIN事件
- 当事件发生时,必须以循环的方式处理时间,知道事件处理完成