你好我在这个问题上生气,因为我使用的是一个简单的模式。 好吧,我有一个无限的时间,我在服务器套接字和已连接的套接字上使用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 in循环来拯救我自己的头,获取缓冲体并且只是为了验证外部循环的空缓冲区我调用一个返回-1的简单recv()(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()会生成另一个请求,我不知道这些内容在哪里是不正确的!