对于epoll来说,当产生epoll调用时,不单是进行了epoll调用。在调用epoll_create()的时候创建了epoll模型,epoll模型分为三部分,红黑树,就绪队列,回调机制。
红黑树,注册epoll事件就是将事件添加至红黑树中,并将想关心的事件也添加进去,该红黑树以文件描述符作为key值;
就绪队列,就绪队列里存放是就绪的文件描述符,当文件描述符就绪时会将其拷贝至就绪队列;
回调机制:底层的一种机制
epoll_ctl()则是对红黑树中文件描述符的操作,可以添加,可以修改,也可以删除。
epoll_wait就是将所有的就绪的文件描述符从内核事件表(相当于就绪队列)中拿出来并放到它的第二个参数的数组中。所以数组中存放的的就会是所有已就绪的文件描述符,而没有其他。极大的提高了查询就绪文件描述符的效率。
client.c/
#include
#include
#include
#include
#include
#include
int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("Usage :./select_client [port]");
return 1;
}
//
struct sockaddr_in client;
client.sin_port = htons(atoi(argv[1]));
client.sin_family = AF_INET;
client.sin_addr.s_addr = htonl(INADDR_ANY);
//创建套接字
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
return 1;
}
//连接服务器
if(connect(sock,(struct sockaddr*)&client,sizeof(client))<0)
{
perror("connect");
return 1;
}
for(;;)
{
//输入消息并刷新缓冲区
printf("client >");
fflush(stdout);
//将消息读到buf里
char buf[1024] = {0};
read(0,buf,sizeof(buf)-1);
//将消息写给文件描述符
if(write(sock,buf,strlen(buf))<0){
perror("write");
continue;
}
//将服务器返回的消息写到buf里
int ret = read(sock,buf,sizeof(buf)-1);
if(ret<0){
perror("read");
continue;
}
if(ret==0)
{
printf("server close\n");
break;
}
printf("server:%s\n",buf);
}
close(sock);
return 0;
}
/
#include
#include
#include
#include
#include
#include
#include
#include
int startup(int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
exit(3);
}
int opt = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(port);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
exit(4);
}
if(listen(sock,5)<0)
{
perror("listen");
exit(5);
}
return sock;
}
void handler_events(int epfd,struct epoll_event revs[],int num,int listen_sock)
{
int i = 0;
struct epoll_event ev;
for(;i0){
buf[s]=0;
printf("%s",buf);
ev.events = EPOLLOUT;
ev.data.fd = fd;
epoll_ctl(epfd,EPOLL_CTL_MOD,fd,&ev);
}
else if(s==0){
printf("client quit");//客户端退出
close(fd);//关闭文件描述符
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);//将文件描述符从epoll模型中去掉
}
}
else{
perror("read");
close(fd);//关闭文件描述符
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);//将文件描述符从epoll模型中去掉
}
continue;
}
if(revs[i].events & EPOLLOUT){
const char* echo = "HTTP/1.1 200 OK\r\n\r\nhello epoll !\n";
write(fd,echo,strlen(echo));
//写完之后
close(fd);//关闭文件描述符
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);//将文件描述符从epoll模型中去掉
}
}
}
//eopll_server 8080
int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("Usage:%s port\n",argv[0]);
return 1;
}
int epfd = epoll_create(256);//绝对是3
if(epfd<0)
{
perror("epoll_create");
return 2;
}
int listen_sock = startup(atoi(argv[1]));
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = listen_sock;//把listen_sock托管起来
epoll_ctl(epfd,EPOLL_CTL_ADD,listen_sock,&ev);
struct epoll_event revs[128];
int n = sizeof(revs)/sizeof(revs[0]);
int timeout = 1000;
int num = 0;
for(;;){
switch((num = epoll_wait(epfd,revs,n,timeout))){
case -1:
perror("epoll_wait");
break;
case 0:
printf("timeout\n");
break;
default:
handler_events(epfd,revs,num,listen_sock);
break;
}
}
close(epfd);
close(listen_sock);
return 0;
}