epoll是linux2.6用于高并发数据处理的接口。
instance analysis1:
send.c
//send.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
int main()
{
int sock;
struct sockaddr_in dest1, dest2;
char buf[1024];
sock = socket(AF_INET, SOCK_DGRAM, 0);
dest1.sin_family = AF_INET;
dest2.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &dest1.sin_addr.s_addr);
inet_pton(AF_INET, "127.0.0.1", &dest2.sin_addr.s_addr);
dest1.sin_port = htons(11111);
dest2.sin_port = htons(22222);
int count = 10;
while(count--)
{
printf("count:%d\n",count);
strcpy(buf, "data to port 11111\n");
//给地址1(dest1)送信
sendto(sock, buf, strlen(buf), 0, (struct sockaddr*)&dest1, sizeof(dest1));
sleep(1);
strcpy(buf, "data to port 22222\n");
//给地址2(dest2)送信
sendto(sock, buf, strlen(buf), 0, (struct sockaddr*)&dest2, sizeof(dest1));
}
close(sock);
return 0;
}
recv.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define EVENTS 12
int main()
{
int sock1, sock2;
struct sockaddr_in addr1, addr2;
int epfd;
struct epoll_event ev, ev_ret[EVENTS];
char buf[2048];
int i;
int nfds;
int n;
//创建2个接受消息的socket
sock1 = socket(AF_INET, SOCK_DGRAM, 0);
sock2 = socket(AF_INET, SOCK_DGRAM, 0);
addr1.sin_family = AF_INET;
addr2.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &addr1.sin_addr.s_addr);
inet_pton(AF_INET, "127.0.0.1", &addr2.sin_addr.s_addr);
addr1.sin_port = htons(11111);
addr2.sin_port = htons(22222);
bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1));
bind(sock2, (struct sockaddr*)&addr2, sizeof(addr2));
//参数不小于0就行
epfd = epoll_create(1);
if(epfd < 0){
perror("epoll_create");
return 1;
}
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;//只读
ev.data.fd = sock1;//把sock1加到epoll
if(epoll_ctl(epfd, EPOLL_CTL_ADD, sock1, &ev) != 0){
perror("epoll_ctl");
return 1;
}
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;//只读
ev.data.fd = sock2;//把sock2加到epoll
if(epoll_ctl(epfd, EPOLL_CTL_ADD, sock2, &ev) != 0){
perror("epoll_ctl");
return 1;
}
while(1)
{
printf("before epoll_wait\n");
//int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
//timeout ms
//在这里会阻塞,只等待10秒,超过10秒,epoll_wait函数结束,返回0给nfds.
nfds = epoll_wait(epfd, ev_ret, EVENTS, 10*1000);
if(nfds < 0)
{
perror("epoll_wait; return 1");
return 1;
}
printf("after epoll_wait\n");
if(nfds == 0)
{
printf("timeout....exit\n");
break;
}
printf("runing nfds:%d\n", nfds);
for(i = 0; i < nfds; ++i)
{
//判断进来的socket是哪个socket
if(ev_ret[i].data.fd == sock1)
{
//从sock1读取数据,并写入到标准输出
n = recv(sock1, buf, sizeof(buf), 0);
write(fileno(stdout), buf, n);
}
//判断进来的socket是哪个socket
else if(ev_ret[i].data.fd == sock2)
{
//从sock1读取数据,并写入到标准输出
n = recv(sock2, buf, sizeof(buf), 0);
write(fileno(stdout), buf, n);
}
}
}
close(sock1);
close(sock2);
return 0;
}
原理
从上面的讲解可知:通过红黑树和双链表数据结构,并结合回调机制,造就了epoll的高效。
OK,讲解完了Epoll的机理,我们便能很容易掌握epoll的用法了。一句话描述就是:三步曲。
第一步:epoll_create()系统调用。此调用返回一个句柄,之后所有的使用都依靠这个句柄来标识。
第二步:epoll_ctl()系统调用。通过此调用向epoll对象中添加、删除、修改感兴趣的事件,返回0标识成功,返回-1表示失败。
第三部:epoll_wait()系统调用。通过此调用收集收集在epoll监控中已经发生的事件。

本文介绍了epoll作为Linux 2.6内核中的高效I/O多路复用技术,通过红黑树和双链表的数据结构实现高性能并发处理。通过实例代码详细展示了如何使用epoll监控多个socket的读事件,包括epoll_create、epoll_ctl和epoll_wait三个关键函数的使用。
569

被折叠的 条评论
为什么被折叠?



