多路复用技术Linux下epoll的边缘触发模式代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#define PORT 65535 //端口号
#define EPOLL_SIZE 1024 //epoll树的最大挂载量
struct epoll_event myevent[EPOLL_SIZE + 1];
int main()
{
int ifError; //是否有错误发生
//创建用于TCP通信的socket
int lfd = socket(AF_INET, SOCK_STREAM, 0);
if(lfd < 0)
{
perror("socket error");
exit(-1);
}
//设置端口复用
int opt = 1;
ifError = setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if(ifError < 0)
{
perror("setsockopt error");
exit(-1);
}
//绑定端口
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
ifError = bind(lfd, (struct sockaddr *)&addr, sizeof(addr));
if(ifError < 0)
{
printf("bind error");
exit(-1);
}
//将lfd改为被动监听状态
ifError = listen(lfd, 128);
if(ifError < 0)
{
perror("listen error");
exit(-1);
}
//初始化epoll树
int epfd = epoll_create(EPOLL_SIZE);
//将监听文件描述符上epoll树
myevent[EPOLL_SIZE].events = EPOLLIN;
myevent[EPOLL_SIZE].data.fd = lfd;
ifError = epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &myevent[EPOLL_SIZE]);
if(ifError < 0)
{
perror("epoll_ctl error");
exit(-1);
}
//循环体中变量定义
int num;
int i;
int cfd;
int sockfd;
int flags;
int n;
char buf[1024];
//持续监控epoll树上挂载的文件描述符及事件
while(1)
{
num = epoll_wait(epfd, myevent, EPOLL_SIZE, -1);
//如果返回值为-1,判断是否被信号打断
if(num < 0)
{
if(errno == EINTR)
{
continue;
}
else
{
perror("epoll_wait error");
exit(-1);
}
}
//处理可读事件
for(i = 0; i < num; i++)
{
sockfd = myevent[i].data.fd;
//有客户端连接
if(sockfd == lfd)
{
//接收客户端连接并上树
cfd = accept(lfd, NULL, NULL);
if(cfd < 0)
{
perror("accept error");
exit(-1);
}
//设置边缘触发,提高效率
myevent[EPOLL_SIZE].events = EPOLLIN | EPOLLET;
myevent[EPOLL_SIZE].data.fd = lfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &myevent[EPOLL_SIZE]);
//将通信文件描述符设为非阻塞
flags = fcntl(cfd, F_GETFL, 0);
flags = flags | O_NONBLOCK;
fcntl(cfd, F_SETFL, flags);
}
//有数据到来
else
{
while(1)
{
bzero(buf, sizeof(buf));
n = read(sockfd, buf, sizeof(buf));
if(n < 0)
{
//暂时没有数据可读
if(errno == EAGAIN)
{
break;
}
//异常
else
{
perror("read errno");
exit(-1);
}
}
//客户端关闭连接
else if(n == 0)
{
epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL);
close(sockfd);
break;
}
//读取到n字节数据
else
{
/*
核心操作
*/
}
}
}
}
}
close(lfd);
return 0;
}