我正试图在Linux中使用epoll()创建一个异步Web服务器,但每当事件epollrdhup发生时,就会出现问题。如果未设置epolloneshot标志,服务器会在循环过程中多次尝试处理无用事件(非epollin或epollout),而不停止,这会导致服务器完全没有响应(并需要重新启动)。当设置了标记epolloneshot时,服务器只会在短时间内(秒)没有响应,然后再次响应(这仍然不理想)。我不确定是什么导致了这种情况,因为每当发生epolldhup时,我都会关闭套接字。这是我的代码:
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;
}
}