2

我编写了一个服务器代码,它接受新客户端和来自客户端的数据。但问题是尽管没有来自客户端的数据,但 select 不会等到超时。我想等待 5 秒钟,然后为可用的客户发送心跳。但它在第一次迭代中等待 5 秒,然后在下一次迭代中快速发送心跳。如何解决这个问题呢。提前致谢。

void * Communicate(void * id)
{
int *iSockID = (int *) id;
int listener =  *iSockID;

fd_set master;    // master file descriptor list
fd_set read_fds;  // temp file descriptor list for select() read
fd_set write_fds; // temp file descriptor list for select() read
int fdmax;        // maximum file descriptor number

int i, j, rv;

FD_ZERO(&master);    // clear the master and temp sets
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
// add the listener to the master set
FD_SET(listener, &master);
printf("Listener is %d \n" , listener);

// keep track of the biggest file descriptor
fdmax = listener; // so far, it's this one
//accept 3 clients


// main loop
for(;;) {
    read_fds = master; // copy it
    write_fds = master;
    struct timeval tv;
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    int iResult = select(fdmax+1, &read_fds, &write_fds, NULL, &tv) ;
    if (iResult == -1) 
    {
        perror("select");
        exit(4);
    }

    for(i = 0; i <= fdmax; i++) 
    {           
        //send work for clients
        SendHeartBeats(write_fds , fdmax , listener , i );

    }

    // run through the existing connections looking for data to read
    // ADD NEW CONNECTIONS READ FROM CONNECTIONS    
    for(i = 0; i <= fdmax; i++)
    {   


        if (FD_ISSET(i, &read_fds)) 
        { // we got one!!
            // handle new connections               
            if (i == listener) 
            {                                    
                AcceptNewClients(master , fdmax , listener );   
            } else 
            {
                AccepeDataFromClients(i , master);
            } // END handle data from client
        } // END got new incoming connection
    } // END looping through file descriptors
    sleep(3);
} // END for(;;)
return 0;
}
4

3 回答 3

1

你不能 fd_set 等式变量。您需要使用 FD_COPY。如果不这样做,您只需将句柄复制到已标记为已完成的实际数据。

于 2013-01-24T07:46:35.173 回答
1

您需要更改代码以在每次调用时重新初始化read_fdand变量,因为它会在退出时修改它们,因此您每次都需要重置它们。正如其他人所说,使用运算符复制变量不是复制结构的正确方法。write_fdselect()=masterfd_set

试试这个:

void * Communicate(void * id)
{
    int *iSockID = (int *) id;
    int listener =  *iSockID;

    fd_set master;    // master file descriptor list
    fd_set read_fds;  // temp file descriptor list for select() read
    fd_set write_fds; // temp file descriptor list for select() read
    struct timeval tv;
    int fdmax;        // maximum file descriptor number
    int i, j, rv;

    printf("Listener is %d \n", listener);

    // add the listener to the master set
    FD_ZERO(&master);
    FD_SET(listener, &master);

    // keep track of the biggest file descriptor
    fdmax = listener; // so far, it's this one
    //accept 3 clients

    // main loop
    clock_t c1 = clock();
    while (1)
    {
        FD_ZERO(&read_fds);
        FD_ZERO(&write_fds);

        #ifdef MSWINDOWS
        // Windows does not have FD_COPY()
        for (u_int i = 0; i < master.fd_count; ++i)
        {
            FD_SET(master.fd_array[i], &read_fd);
            FD_SET(master.fd_array[i], &write_fd);
        }
        #else
        FD_COPY(&master, &read_fd);
        FD_COPY(&master, &write_fd);
        #endif

        tv.tv_sec = 1;
        tv.tv_usec = 0;

        int iResult = select(fdmax+1, &read_fds, &write_fds, NULL, &tv);
        if (iResult == -1) 
        {
            perror("select");
            exit(4);
        }

        clock_t c2 = clock();
        if (((c2-c1) / CLOCKS_PER_SEC) >= 5)
        {
            c1 = c2;
            for(i = 0; i <= fdmax; i++) 
            {           
                if ((i != listener) && FD_ISSET(i, &write_fds))
                { 
                    //send work for client
                    SendHeartBeat(i);
                }
            }
        }

        // run through the existing connections looking for data to read
        // ADD NEW CONNECTIONS READ FROM CONNECTIONS    
        for(i = 0; i <= fdmax; i++)
        {   
            if (FD_ISSET(i, &read_fds)) 
            {
                // we got one!!
                if (i == listener) 
                {                                    
                    AcceptNewClient(master, fdmax, listener);   
                }
                else 
                {
                    AcceptDataFromClient(i);
                }
            }
        }
    }

    return 0;
}
于 2013-01-24T10:11:33.863 回答
0

您在您正在使用的评论中声明Linux 2.6.27。由于在 Linux 中,anfd_set是一个包含整数类型数组的结构,因此使用赋值复制masterread_fds是可以的。

您的select呼叫没有被阻塞的原因是因为您正在初始化read_fdswrite_fdsfrom master。您的空闲客户端套接字始终是可写的,因此您会立即醒来。顺便说一句,在您的listener套接字上选择可写是没有意义的。

您应该只在write_fds尝试写入但收到EAGAIN/EWOULDBLOCK错误时设置客户端套接字。

于 2013-03-13T18:49:56.153 回答