ePoll不接受某些客户

时间:2018-03-04 16:38:04

标签: c linux networking epoll

我已经使用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,我会看到相同的行为。我原本以为这可能是边缘触发行为的结果,但是没有。

1 个答案:

答案 0 :(得分:0)

listen()的backlog参数是否大于客户端数量?

@ some-programmer-dude,抱歉没有评论,关闭的fd将自动从epoll事件中删除http://man7.org/linux/man-pages/man7/epoll.7.html