【发布时间】:2019-05-29 13:55:18
【问题描述】:
我正在尝试在 Linux 中使用 epoll() 创建一个异步 Web 服务器,但是每当 EPOLLRDHUP 事件发生时就会出现问题。当未设置标志 EPOLLONESHOT 时,服务器会在循环期间多次尝试处理无用事件(不是 EPOLLIN 或 EPOLLOUT)而不停止,这会导致服务器完全无响应(并需要重新启动)。当设置了 EPOLLONESHOT 标志时,服务器会在短时间内(秒)变得无响应,然后再次响应(这仍然不理想)。我不确定是什么原因造成的,因为每当发生 EPOLLRDHUP 时我都会关闭套接字。这是我的代码:
int server_fd, new_socket;
long valRead;
struct sockaddr_in address;
int addrlen = sizeof(address);
//setup code (bind(), etc.) would be here
struct connection {
int socket;
unsigned int connectionType;
void* dataToSend;
unsigned int dataByteSize;
struct epoll_event event;
bool active;
};
struct connection* connections = (struct connection*)malloc(1000 * sizeof(struct connection));
connections[0].socket = server_fd;
connections[0].connectionType = 1U;
connections[0].event.events = EPOLLIN;
connections[0].event.data.ptr = &connections[0];
unsigned int connectionIndex = 1U;
fcntl(server_fd, F_SETFL, O_NONBLOCK);
int epollFd = epoll_create(10);
epoll_ctl(epollFd, EPOLL_CTL_ADD, server_fd, &connections[0].event);
struct epoll_event* receivedEvents = malloc(sizeof(struct epoll_event) * 1000);
struct connection currentConnection;
#define MAX_EVENTS 10
int numEventsReady;
unsigned int eventIndex;
while (1) {
printText("\n+++++++ Waiting for new connection ++++++++\n\n", 46);
numEventsReady = epoll_wait(epollFd, receivedEvents, MAX_EVENTS, -1);
if (numEventsReady == -1) {
printf("\nErrno:");
printf("%i", errno);
printf("\n");
fprintf(stderr, "epoll_wait() failed: %s\n", strerror(errno));
exit(7);
}
eventIndex = 0U;
while (eventIndex < numEventsReady) {
currentConnection = *((struct connection*)receivedEvents[eventIndex].data.ptr);
switch (currentConnection.connectionType) {
case 1U:
//printText("\nConnected", 10);
new_socket = accept4(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (new_socket != -1) {
connections[connectionIndex].socket = new_socket;
connections[connectionIndex].connectionType = 2U;
connections[connectionIndex].event.events = EPOLLIN | EPOLLRDHUP;
connections[connectionIndex].event.data.ptr = &connections[connectionIndex];
epoll_ctl(epollFd, EPOLL_CTL_ADD, new_socket, &connections[connectionIndex].event);
++connectionIndex;
}
break;
case 2U:
if (receivedEvents[eventIndex].events & EPOLLERR) {
printf("\nEPOLLERR\n");
close(currentConnection.socket);
}
else if(receivedEvents[eventIndex].events & EPOLLHUP) {
printf("\nEPOLLHUP\n");
close(currentConnection.socket);
}
else if(receivedEvents[eventIndex].events & EPOLLRDHUP) {
printf("\nEPOLLRDHUP\n");
close(currentConnection.socket);
}
else if (receivedEvents[eventIndex].events & EPOLLIN) {
valRead = recv(currentConnection.socket, buffer, 65536, 0);
if (valRead < 1) {
printf("recv error");
if (errno != EAGAIN && errno != EWOULDBLOCK) {
printf("errno != EAGAIN && errno != EWOULDBLOCK");
close(currentConnection.socket);
}
break;
}
printText(buffer, valRead);
currentConnection.event.events = EPOLLOUT | EPOLLRDHUP;
currentConnection.event.data.ptr = ¤tConnection;
epoll_ctl(epollFd, EPOLL_CTL_MOD, currentConnection.socket, ¤tConnection.event);
if (buffer[0] == 'G' && buffer[1] == 'E' && buffer[2] == 'T') {
switch (buffer[5]) {
case ' ': //default web page (index.htm)
currentConnection.dataToSend = indexHtm;
currentConnection.dataByteSize = sizeof(indexHtm);
//sendSocketData(new_socket, indexHtm, sizeof(indexHtm));
break;
}
}
else if (receivedEvents[eventIndex].events & EPOLLOUT) {
valRead = send(currentConnection.socket, currentConnection.dataToSend, currentConnection.dataByteSize, 0);
if (valRead == -1) {
printf("send error has ocurred\n");
if (errno != EAGAIN && errno != EWOULDBLOCK) {
printf("\nerrno != EAGAIN && errno != EWOULDBLOCK\n");
close(currentConnection.socket);
}
break;
}
currentConnection.event.events = EPOLLIN | EPOLLRDHUP;
currentConnection.event.data.ptr = ¤tConnection;
valRead = epoll_ctl(epollFd, EPOLL_CTL_MOD, currentConnection.socket, ¤tConnection.event);
}
break;
}
++eventIndex;
}
}
【问题讨论】:
-
您的代码示例有点过于复杂。你能把代码缩减为等待循环和套接字的关闭以及创建循环的方法吗?
-
什么是
MAX_EVENTS? -
@jxh 10,传入epoll_wait()的maxevents参数中
-
以上是尝试重现您的问题,但没有无限循环。
标签: c linux sockets asynchronous epoll