你好,我对这个问题很生气,因为我使用的是一个简单的模式。好的,我有一个无限的时间,我在服务器套接字上使用 epoll_wait 并且已经连接了套接字。如果新套接字发送连接请求,一切正常;我的问题是当连接的套接字(现在我只使用一个发送 390k 数据包的套接字)发送数据时:无论我使用 EPOLLONESHOT 还是 EPOLLET,在消耗完该套接字上的所有请求缓冲区、重新配置套接字或在 recv 上接收 EAGAIN 之后( ), epoll_wait 总是用错误的缓冲区再次唤醒!我的服务器使用线程池,但现在只是一个可以完成所有工作的线程(以简化测试):
while (TRUE) {
int num = epoll_wait(efd, events, MAX_EVENTS, -1);
for (int i = 0; i < num; i++) { // ciclo epoll()
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP || !(events[i].events & EPOLLIN)) {
fprintf (stderr, "epoll error on socket: closed\n");
s = epoll_ctl(efd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
}
else if (events[i].data.fd == serverSocket) {
while (TRUE) {
newInfoClient = server->m_bgServer->AcceptClient(&newSocketClient);
if (newInfoClient == NULL) { // nessun client
break;
}
else {
printf("\nSocket accettato: %d", newSocketClient);
s = CSocket::MakeNonBlocking(newSocketClient);
if (s == -1)
abort();
event.data.fd = newSocketClient;
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_ADD, newSocketClient, &event);
if (s == -1) {
abort();
}
}
}
else {
AbstractTcpServerGame::DownloadTcpRequest(client);
}
}
}
我刚刚省略了一些检查和其他内部代码。AbstractTcpServerGame::DownloadTcpRequest(...) 这个函数只是一个循环中的 recv 来拯救我自己的标头,获取缓冲区主体并只是为了验证循环外的空缓冲区我调用一个简单的 recv() 返回 -1(errno=EAGAIN 或EWOULDBLOCK)。在此之后,当我在 EPOLLONESHOT 情况下的 DownloadTcpRequest() 中使用 epoll_ctr() 重新配置套接字时,当它返回时,epoll_wait() 在同一个套接字上再次唤醒!这是我的执行日志:
New socket (6) request (errno 11) <--- when epoll_wait() emits EPOLLIN on socket 6
Download of 18 bytes (socket 6) <-- inside AbstractTcpServerGame::DownloadTcpRequest()
Download of 380k (socket 6) <-- another recv() loop to rescue body request
------------------- empty buffer on socket 6 ----------- <-- dummy recv to show empty buffer
New socket (6) request (errno 11)
Download of 18 bytes (socket 6)
Download of -1556256155 (socket 6)
Error on socket 6 (bad::alloc exception)
客户端发送 398k(18 标头 + 正文)并且所有数据都正确接收,如上所示,但是重新配置套接字或使用 EPOLLET,epoll_wait() 会生成另一个请求,我不知道这些请求实际上是不正确的!