Select 尝试从文件描述符读取 activity 时阻塞

Select blocks when trying to read activity from file descriptors

我正在尝试创建一个接受多个客户端的服务器。这是我的代码的一部分。我的服务器需要 listen 到两个 ports。实现这一目标的 socketsfd_servfd_comm.

使用 selectnonblock 文件描述符,不幸的是没有给我想要的输出。问题是 select accepts 第一个 client 然后阻塞,并且不读取来自其他 clients.

的消息

另外由于某些原因,如果我不使用 usleep(100000) 命令,我的程序会成功接受但不会继续。

感谢任何帮助。

FD_ZERO(&set);
FD_SET(fd_serv, &set);
FD_SET(fd_comm, &set); 
while (1)
    {
    if (select (max_fd + 1, &set, NULL, NULL, NULL) < 0)
    {
        perror ("select");
        exit (EXIT_FAILURE);
    }

    for (i = 1; i < max_fd + 1; i++)
    {
        usleep(100000);
        if (FD_ISSET (i, &set))
        {
            if (i == fd_serv)       //Connection request on original socket.
            {
                new_serv = accept (fd_serv, (struct sockaddr *) &client_serv_addr, &sin_len_serv);
                if (new_serv < 0){ perror ("accept"); exit (EXIT_FAILURE); }
                fd_set_blocking(new_serv, 0);
                FD_SET(new_serv, &set);
                max_fd = max(max_fd, new_serv);
            }
            else if (i == fd_comm)  //Connection request on original socket.
            {
                new_comm = accept (fd_comm, (struct sockaddr *) &client_comm_addr, &sin_len_comm);
                if (new_comm < 0){ perror ("accept"); exit (EXIT_FAILURE); }
                fd_set_blocking(new_comm, 0);
                FD_SET (new_comm, &set);
                max_fd = max(max_fd, new_comm);
            }
            else if (i == new_comm) //Activity on already connected socket
            {
                if (read_command(fd_comm, i, start_time) == 1)
                {
                    close(i);
                    FD_CLR(i, &set);
                    return SHUTDOWN;
                }
            }
            else if (i == new_serv) //Activity on already connected socket
            {
                read_service(i);
                close(i);
                FD_CLR(i, &set);
            }
        }
    }
}

你的问题在这里:

FD_ZERO(&set);
FD_SET(fd_serv, &set);
FD_SET(fd_comm, &set); 
while (1) 
{
   [...]

您只设置了您的 fd_set 一次,但是您的 fd_set 将被 select() 调用修改,因此您需要在循环的每次迭代中设置一次.试试这个:

while (1) 
{
   FD_ZERO(&set);
   FD_SET(fd_serv, &set);
   FD_SET(fd_comm, &set); 
   const int max_fd = (fd_serve > fd_comm) ? fd_serve : fd_comm;
   [...]

...在 select() 调用之后,您应该调用的唯一 select() 相关的东西是 FD_ISSET()。所有其他的东西都是毫无意义的,因为你额外的 FD_SET()FD_CLR() 调用正在修改一个 fd_set ,你只需在开始时用 FD_ZERO() 调用擦除下一次 while 循环迭代。

此外,作为旁注:usleep(10000) 呼叫应该消失——如果您正确呼叫 select(),则在 select() 之外的任意时间段休眠都不是必要也不可取。