I/O多路转接之epoll模型
程序员文章站
2022-06-14 14:40:44
...
epoll是性能最好的没有之一
epoll有三个系统调用函数
epoll_create 创建文件描述符、来标识epoll模型
epoll_ctl
epoll_wait
#include<stdio.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#define SIZE 64
static void Usage(char*proc)
{
printf("%s [local_ip] [local_port]\n",proc);
}
int startUp(char*ip,int port)
{
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
exit(2);
}
int opt=1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(atoi(port));
server.sin_addr.s_addr=inet_addr(ip);
if(bind(sock,(struct sockaddr*)&server,sizeof(struct sockaddr_in))<0)
{
perror("bind");
exit(3);
}
if(listen(sock,10)<0)
{
perror("listen");
exit(4);
}
return sock;
}
int main(int argv,char*argc[])
{
if(argv!=3)
{
Usage(argc[0]);
return 1;
}
int listen_sock=startUp(argc[1],argc[2]);
int epfd= epoll_create(256);
if(epfd<0)
{
perror("epoll_create");
return 5;
}
struct epoll_event ev;
ev.events=EPOLLIN;
ev.data.fd=listen_sock;
epoll_ctl(epfd,EPOLL_CTL_ADD,listen_sock,&ev);
struct epoll_event revs[64];
int nums=-1;
int timeout=5000;
while(1)
{
switch((nums=epoll_wait(epfd,revs,SIZE,timeout)))
{
case -1:
perror("epoll_wait");
return 6;
case 0:
printf("timeout\n");
break;
default:
{
int i=0;
for(i=0;i<nums;i++)
{
printf("nums %d\n",nums);
int fd=revs[i].data.fd;
if(fd==listen_sock&&revs[i].events&EPOLLIN)
{
struct sockaddr_in client;
socklen_t len=sizeof(client);
int newsock=accept(listen_sock,(struct sockaddr*)&client,&len);
if(newsock<0)
{
perror("accept");
continue;
}
printf("get a client [%s] [%d]\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
ev.events=EPOLLIN;
ev.data.fd=newsock;
epoll_ctl(epfd,EPOLL_CTL_ADD,newsock,&ev);
}
else if(fd!=listen_sock)
{
printf("hahah\n");
if(revs[i].events&EPOLLIN)
{
char buf[1024];
ssize_t s=read(fd,buf,sizeof(buf)-1);
if(s>0)
{
buf[s]=0;
printf("client say:%s\n",buf);
ev.events=EPOLLOUT;
ev.data.fd=fd;
epoll_ctl(epfd, EPOLL_CTL_MOD,fd,&ev);
}
else if(s==0)
{
printf("client is quit\n");
close(fd);
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,&ev);
}
else
{
perror("read");
close(fd);
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,&ev); }
}
else if(revs[i].events&EPOLLOUT)
{
const char* msg = "HTTP/1.1 200 OK\r\n\r\n<html><h1>Hello epoll!</h1></html>";
write(fd,msg,strlen(msg));
close(fd);
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,&ev);
}
else
{
}
}
else
{
}
}
}
break;
}
}
return 0;
}
epolls是一种高性能服务器。
1、他底层的红黑树能够高效的进行增删改查
2、采用回调机制不需要轮询
3、一旦关心的文件描述符上对应的事件发生就**放入就绪队列
4、上层直接从就绪队列中取
5、就绪队列连续并且返回值是实际就绪的个数,这样即使需要遍历也会遍历的都是有效的
6、采用内存映射机制,少了数据的拷贝。