1.EPOLLLT和EPOLLET最大的区别在于事件的通知机制,看这个文章EPOLLLT和EPOLLET的区别
2.EPOLLET模式下并不意味着要循环读取完缓冲区的所有数据,贴出一段读取代码:
n = 0;
while ((nread = read(fd, buf + n, BUFSIZ-1)) > 0) {
n += nread;
}
if (nread == -1 && errno != EAGAIN) {
perror("read error");
}
这段代码的陷阱在于,如果tcp缓冲区可读数据比buf大,那么将会造成堆栈溢出,所以循环读取缓冲区数据直到遇到EAGAIN并不是正确的做法。
3.需要注意的是,首次增加和每次修改套接字的events时,都需要指明EPOLLET,并不是ADD一次后就会永久是EPOLLET模式
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET; /* ET模式 */
ev.data.fd = sockfd;
if (-1 == epoll_ctl(efd, EPOLL_CTL_ADD, sockfd, &ev)) {
perror("epoll_ctl EPOLL_CTL_ADD fail");
}
5.EPOLLLT和EPOLLET在发送数据时的行为是一致的,都需要应用层主动判定是否有数据可发送
epoll_event结构体的理解
// man 2 epoll_ctl
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
测试代码:
----- server.cpp -----
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#define MAX_EVENTS 1000
#define MAX_LEN 1024
/*
参考 man epoll_ctl
EPOLLIN 可读
EPOLLOUT 可写
EPOLLPRI 紧急数据
EPOLLRDHUP 出错
EPOLLERR 出错
EPOLLHUP 出错
*/
//设置非阻塞
static void setnonblocking(int sockfd) {
int flag = fcntl(sockfd, F_GETFL, 0);
if (flag < 0) {
perror("fcntl F_GETFL fail");
return;
}
if (fcntl(sockfd, F_SETFL, flag | O_NONBLOCK) < 0) {