#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/select.h>
#include <poll.h>
#include <netdb.h>
#include <limits.h>
#include <sys/epoll.h>
#define ip "127.0.0.1"
#define port 8888
#define MAXSIZE 3
int main(int argc, char* argv[])
{
int afd, sfd;
struct sockaddr_in servaddr;
//创建socket文件描述符
sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd == -1)
{
perror("sfd == -1");
exit(1);
}
//防止端口复用
int reuse = 1 ;
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse, sizeof(reuse));
//初始化socket
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port) ;
servaddr.sin_addr.s_addr = inet_addr(ip);
//绑定套接字
if(bind(sfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
{
perror("bind error");
exit(1);
}
//监听套接字
if(listen(sfd, 5) == -1)
{
perror("listen error");
exit(1);
}
int epfd = epoll_create(MAXSIZE);
if(epfd == -1)
{
perror("epoll_create");
exit(1);
}
struct epoll_event ev;
ev.data.fd = sfd;
ev.events = EPOLLIN;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &ev) == -1)
{
perror("epoll_ctl");
exit(1);
}
int nfd;
struct epoll_event evlist[MAXSIZE];
//evlist = &ev;
while(1)
{
nfd = epoll_wait(epfd, evlist, MAXSIZE, 0);
if(nfd == -1)
{
perror("epoll_wait");
exit(1);
}
for(int i = 0; i < nfd; ++i)
{
if(evlist[i].events & EPOLLIN)
{
if(evlist[i].data.fd == sfd)
{
afd = accept(sfd, NULL, NULL);
ev.data.fd = afd;
ev.events = EPOLLIN;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, afd, &ev) == -1)
{
perror("epoll_ctl");
exit(1);
}
}else
{
int readn;
char buf[10];
memset(buf, 0, 10);
if((readn = read(evlist[i].data.fd, buf, 10)) < 0)
{
perror("read error");
exit(1);
}
if(readn == 0)
{
ev.data.fd = evlist[i].data.fd;
ev.events = EPOLLIN;
epoll_ctl(epfd, EPOLL_CTL_DEL, evlist[i].data.fd, &ev);
close(evlist[i].data.fd);
}else
{
printf("%s\n", buf);
}
}
}
}
}
close(epfd);
close(sfd);
return 0;
}
epoll有边界触发和水平触发两种方式,select/poll只有一种
et会把进来的连接和数据一次给你,如果你一次没有全部取完下次就不会给你了,lt只要这次没有被取走下次还能取到,et触发系统调用次数少
两者的区别:
比如说你从某宝下单买了几个东西,这几个东西分别由N个快递员分别给你送过来。在某一时刻,你开始等快递。
对于select/poll,就是你在睡觉的时候,收到一条短信“你有快递到了,取一下”,但不知道发送方是谁(但一定是那N个快递员中的某人/某几个人给你发的),所以你必须挨个给那N个快递员分别打个电话,问他们,是不是我的快递已经到了。
至于select/poll的区别,类似于你和快递员都分别有两个手机号,一个移动,一个联通,其区别就在于你用哪个手机号给他们打的问题。
对于epoll,是你收到那条短信的时候,看到了发送方的电话号码,你就可以直接给他打电话,问他在哪儿,你好去去快递。
还可以形象一点
select/poll
饭店服务员(内核)告诉饭店老板(用户程序):”现在有客人结账“
但是这个服务员没人明确告诉老板,哪几桌的客人结帐。老板得自儿一个一个桌子去问:请问是你要结帐?
epoll
饭店服务员(内核)告诉饭店老板(用户程序):”1,2,5号客人结账“
老板就可以直接去1,2,5号桌收钱了