函数原型:
#include <sys/epoll.h>
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
函数解析:
1 .epoll_create:创建epoll句柄,占一个fd值,需要用close释放
2. epoll_ctl:事件注册函数,与select选择监听什么类型的事件不同,epoll由此函数注册要监听的事件是什么类型的
(1)参数epfd:由epoll_create创建的fd
(2)参数op:表示要执行哪种操作,由三个宏区分
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删除一个fd。
(3)参数fd:需要监听的套接字fd
(4)参数event:要监听的事件类型是什么,大体分为:
EPOLLIN:表示对应的文件描述符可读; EPOLLOUT:表示对应的文件描述符可写; EPOLLPRI:表示对应的文件描述符有紧急数据可读; EPOLLERR:表示对应的文件描述符发生错误; EPOLLHUP:表示对应的文件描述符被挂断; EPOLLET:将EPOLL设为边缘触发(只有数据到来才触发,不管缓存区的其他数据),这是相对于水平触发(只要有数据就触发)而言的。
3. epoll_wait :用于收集在epoll监控的事件中已经发生的事件,返回值为发生的事件个数;
(1)参数events:是个epoll_event结构体数组的指针,得自己申请空间,不能放空指针
(2)参数maxevents:events数组有多大,值不能大于初始化create时后的size
(3)timeout:超时时间
#include <iostream>
#include "common_n.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#define MAX_N 200
#define PORT 8888
using namespace std;
int main() {
int listen_socket = socket_create(PORT);
int ep_fd = epoll_create(MAX_N);
if (ep_fd < 0) {
perror("epoll_create");
exit(1);
}
struct epoll_event ev, events[MAX_N];
ev.data.fd = listen_socket;
ev.events = EPOLLIN | EPOLLET;
if (epoll_ctl(ep_fd, EPOLL_CTL_ADD, listen_socket, &ev) < 0) {
perror("epoll_ctl");
exit(0);
}
unsigned long ul = 1;
ioctl(listen_socket, FIONBIO, &ul);
int nfds;
while (1) {
nfds = epoll_wait(ep_fd, events, MAX_N, 5*1000);
if (nfds < 0) {
perror("epoll_wait");
exit(1);
}
if (nfds == 0) {
cout << "time out" << endl;
}
for (int i = 0; i < nfds; i++) {
//加入
if (events[i].data.fd == listen_socket) {
int new_sock = accept(listen_socket, NULL, NULL);
if(new_sock < 0) {
perror("accept");
exit(1);
}
cout << "someone comes" << endl;
ioctl(new_sock, FIONBIO, &ul);
ev.data.fd = new_sock;
ev.events = EPOLLIN | EPOLLET;
if (epoll_ctl(ep_fd, EPOLL_CTL_ADD, new_sock, &ev) < 0){
perror("epoll_ctl : new_sock");
nfds += 1;
continue;
}
} else { //通讯
int client_fd = events[i].data.fd;
char buff[1024] = {0};
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
getpeername(client_fd, (struct sockaddr*)&addr, &len);
if (recv(client_fd, buff, 1024, 0) <= 0) {
cout << "some leave" << endl;
epoll_ctl(ep_fd, EPOLL_CTL_DEL, client_fd, &ev);
close(client_fd);
nfds --;
continue;
}
//printf("%s : %s",inet_ntoa(addr.sin_addr), buff);
cout << inet_ntoa(addr.sin_addr) << "--->" << buff << endl;
send(client_fd, buff, strlen(buff), 0);
}
}
}
close(listen_socket);
return 0;
}