epoll检测的文件描述符只有两种,一种是监听描述符lfd,还有一种是连接描述符cfd,就是用来和客户端进行数据交流的。
在struct task结构体中记录了各种操作所需要的参数,todo函数为要进行的操作,arg为指针,指向自己
epoll中data端使用ptr段来找到任务所需要的task
epoll+反应堆示意图
#include<unistd.h>
#include<cstdio>
#include<iostream>
#include<sys/socket.h>
#include<sys/epoll.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<memory.h>
using namespace std;
struct task {
int fd;
void* (*todo)(void*);//需要执行的操作
void* arg;//指向自身的指针todo函数通过这个指针来找到执行所需要的所有数据
char buf[128];//存放客户端数据
int readlen;//读到数据的长度
int epfd;
//struct epoll_event event;
task() {
fd = 0;
todo = nullptr;
arg = nullptr;
memset(buf, 0, sizeof(buf));
readlen = 0;
epfd = 0;
}
};
struct task task[1024];
void addtask(struct task* t,int epfd,void *(*todo)(void *),int position,int fd) {
t[position].todo = todo;
t[position].arg = &(task[position]);
t[position].epfd = epfd;
t[position].fd = fd;
return;
}
void* cfdtodo(void* arg) {
struct task* t = (struct task *)arg;
t->readlen = read(t->fd, t->buf, sizeof(t->buf));
if (t->readlen < 0) {
perror("read error");
exit(1);
}
else if (t->readlen > 0) {
write(STDOUT_FILENO, t->buf, t->readlen);
write(t->fd, t->buf, t->readlen);
}
else {
close(t->fd);
epoll_ctl(t->epfd, EPOLL_CTL_DEL, t->fd, nullptr);
printf("connect close\n");
}
return nullptr;
}
void* lfdtodo(void* arg) {
struct task *ntask=(struct task *)arg;
struct sockaddr_in client;
socklen_t len = sizeof(client);
int fd = accept(ntask->fd,(struct sockaddr *)&client,&len);
if (fd < 0) {
perror("accept error");
exit(1);
}
int i = 0;
for (i = 1; i < 1024; i++) {
if (ntask[i].fd == 0) {
break;
}
}
addtask(ntask, ntask->epfd, cfdtodo, i, fd);
struct epoll_event ev;
ev.data.ptr = &ntask[i];
ev.events = EPOLLIN;
epoll_ctl(ntask->epfd, EPOLL_CTL_ADD, fd, &ev);
return nullptr;
}
struct epoll_event evl, evs[64];
int main()
{
int lfd = socket(AF_INET, SOCK_STREAM, 0);
int epfd = epoll_create(1);
struct sockaddr_in myaddr;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(9999);
myaddr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(lfd, (struct sockaddr*)&myaddr, sizeof(myaddr));
if(ret < 0){
perror("bind error");
exit(1);
}
ret = listen(lfd, 128);
if (ret < 0) {
perror("listen error");
exit(1);
}
evl.data.ptr = &task[0];
evl.events = EPOLLIN;
addtask(task, epfd, lfdtodo, 0, lfd);
epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &evl);
while (1) {
int nready = epoll_wait(epfd, evs, 64, -1);
if (nready < 0) {
perror("epoll_wait error");
continue;
}
else if (nready > 0) {
for (int i = 0; i < nready; i++) {
((struct task*)(evs[i].data.ptr))->todo(((struct task*)(evs[i].data.ptr))->arg);//---------------------------------------------------
}
}
}
//printf("%s 向你问好!\n", "epoll");
return 0;
}