我已经使用epoll实现了一个服务器,我认为这是标准方式,事实上,当我使用epoll手册页中的示例实现它时,我得到了相同的行为。
这让我相信我的客户肯定存在问题,而且我在某种程度上做了我不应该做的假设。我的客户端的主要方法是分叉n个客户端,然后连接到服务器。我所看到的是,通常这些客户的一部分不会触发epoll,而且永远不会触及 accept()调用。三次握手完成是因为有一个侦听套接字,所以客户端的行为就好像它被接受了一样,但它永远不会被服务,因为服务器并不知道它。我无法弄清楚为什么会这样,并且无法在网上找到类似的问题。想法?
以下是相关的服务器代码:
// wrapper which binds to port and exits on error
listenFD = tcpSocket(host, port);
SetNonblocking(listenFD);
// wrapper which listens and exits on error
tcpListen(listenFD);
epollFD = epoll_create(EPOLL_QUEUE_LEN);
if (epollFD == -1)
errSystem("epoll_create");
// Add the server socket to the epoll event loop
event.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLET;
event.data.fd = listenFD;
if (epoll_ctl (epollFD, EPOLL_CTL_ADD, listenFD, &event) == -1)
errSystem("epoll_ctl");
while(TRUE){
//struct epoll_event events[MAX_EVENTS];
numFDs = epoll_wait(epollFD, events, EPOLL_QUEUE_LEN, -1);
for (i = 0; i < numFDs; i++){
// Case 1: Error condition
if (events[i].events & (EPOLLHUP | EPOLLERR)){
errMessage("epoll: EPOLLERR");
Close(events[i].data.fd);
printf("Closed connection to %d\n", events[i].data.fd);
fflush(stdout);
continue;
}
// Case 2: Server is receiving a connection request
if (events[i].data.fd == listenFD){
// socketlen_t
clientLen = sizeof(client);
newFD = Accept (listenFD, (SA *)&client, &clientLen);
SetNonblocking(newFD);
// Set receive low water mark to message size
SetSockOpt(newFD, SOL_SOCKET, SO_RCVLOWAT, &lowWater, sizeof(lowWater));
// Add the new socket descriptor to the epoll loop
event.data.fd = newFD;
event.events = EPOLLIN | EPOLLET;
if (epoll_ctl (epollFD, EPOLL_CTL_ADD, newFD, &event) == -1)
errSystem ("epoll_ctl");
printf("Connected to client on socket %d\n", newFD);
// tell the client we're connected and ready
// (this is an attempt to fix my issue. I'd rather not do this...)
Writen(newFD, buffer, CLIENT_MESSAGE_SIZE);
continue;
}
if (events[i].events & EPOLLIN){
//serve the client
}
}
}
这是客户端代码。这些作品的一个实例,但如果我分叉超过5个(有时只有2个),其中一些人不会被接受。
int Client(const char *host, const int port, const int timeLen, const int clientNum){
long double delta;
PTSTRUCTS ptstructs = (PTSTRUCTS) malloc(sizeof(TSTRUCTS));
size_t result;
stop = FALSE;
cNum = clientNum;
Signal(SIGINT, closeFD);
Signal(SIGALRM, sendMessage);
nsockets = 0;
// wrapper which calls connect() and exits with message on error
connectFD = tcpConnect(host, port);
printf("%d connected to server:\n", clientNum);
fflush(stdout);
bzero(sbuf, CLIENT_MESSAGE_SIZE);
// initialize client message
strcpy(sbuf, CLIENT_MESSAGE);
// get the start time
getStartTime(ptstructs);
getEndTime(ptstructs);
while((delta = getTimeDelta(ptstructs)) < timeLen){
// One or more clients blocks here for ever
if ((result = receiveMessage()) < CLIENT_MESSAGE_SIZE){
break;
}
//sendMessage();
alarm(1);
//delay(USER_DELAY);
getEndTime(ptstructs);
}
stop = TRUE;
Close (connectFD);
getEndTime(ptstructs);
delta = getTimeDelta(ptstructs);
printf("Client %d served %ld bytes in %.6Lf seconds.\n", clientNum, byteCount, delta);
fflush(stdout);
// free heap memory
free(ptstructs);
return (1);
}
我应该注意到,如果我没有设置EPOLLET,我会看到相同的行为。我原本以为这可能是边缘触发行为的结果,但是没有。
答案 0 :(得分:0)
listen()的backlog参数是否大于客户端数量?
@ some-programmer-dude,抱歉没有评论,关闭的fd将自动从epoll事件中删除http://man7.org/linux/man-pages/man7/epoll.7.html