user-0 提问: FD_SET之后, select不到的问题

回复:
user: user-0
content: 哎，沦落到自己顶一下的地步了。

user: user-0
content: 感谢两位的回答，我代码删多了，引起了大家的误会的，我关心的fd其实是动态的。 就是每次select的fd数量，都是不一定的。 每次发给子进程信息后，都会等待子进程返回，不同的子进程，管道描述符也不一样，因此FD_SET的fd也是不一样的， 现在我将代码完善一下，发给出来。  这是发生问题的代码，就是说只能select到最后一个mypid[i].fd，前几个进程的返回都没有触发select:      FD_ZERO(&rset);       FD_SET(listenfd, &rset);       for(;;)      {           nselect = select(fdmax+1, &rset, NULL, NULL, NULL);         if( FD_ISSET(listenfd, &rset) ) {       /*收到客户端连接请求*/               connfd = accept(listenfd, (SA *)&clientaddr, (socklen_t *)&len);               //此处省略循环找mypid中的第一个status为空闲的，因此两次请求 i 是不同的值。fd也是不同的。              FD_SET(mypid[i].fd, &rset);             /*加入描述集，等待子进程*/               fdmax = max(fdmax ,mypid[i].fd);               //此处省略把连接套接字传送给子进程             close(connfd);                                        if(--nselect  ==0)                   continue;           }           else          {               for(i = 0; i < nchild; i++ )              {                 if(FD_ISSET(mypid[i].fd , &rset))                  {                     read(mypid[i].fd, &c, 1);                       FD_CLR(mypid[i].fd, &rset);                       mypid[i].status = IDLE;                     nselect--;                 }                 if(nselect  == 0)                       break;               }         }     }   }  这是修改之后的,问题解决了，但是不知道为什么，其实就加了一个oset作为临时变量,ISSET和SET不是同一个了。      FD_ZERO(&oset);       FD_ZERO(&rset);       FD_SET(listenfd, &rset);       for(;;)      {           rset = oset;         nselect = select(fdmax+1, &rset, NULL, NULL, NULL);         if( FD_ISSET(listenfd, &rset) ) {       /*收到客户端连接请求*/               connfd = accept(listenfd, (SA *)&clientaddr, (socklen_t *)&len);               //此处省略循环找mypid中的第一个status为空闲的，因此多次请求 i 是不同的值。fd也是不同的。              FD_SET(mypid[i].fd, &oset);             /*加入描述集，等待子进程*/               fdmax = max(fdmax ,mypid[i].fd);               //此处省略把连接套接字传送给子进程             close(connfd);                                        if(--nselect  ==0)                   continue;           }           else          {               for(i = 0; i < nchild; i++ )              {                 if(FD_ISSET(mypid[i].fd , &rset))                  {                     read(mypid[i].fd, &c, 1);                       FD_CLR(mypid[i].fd, &oset);                       mypid[i].status = IDLE;                     nselect--;                 }                 if(nselect  == 0)                       break;               }         }     }   }

user: user-1
content: 引用 7 楼 icesky1stm 的回复:噢，我理解了。 是select 调用之后，就会重置readfds 。 比如， 我FD_SET 了，3,4,5,6  四个文件描述符，然后调用select ,当select返回描述符4可读的时候， 3 ,5,6这三个描述符也被FD_CLR了。 如果要继续select 3,5,6 就必须再调用select之前重新FD_SET。  是的，还要注意的是select的最后一个参数timeout int select(int nfds, fd_set *restrict readfds,        fd_set *restrict writefds, fd_set *restrict errorfds,        struct timeval *restrict timeout);  Upon successful completion, the select() function may modify the object pointed to by the timeout argument  所以要用这个参数的话，在循环里每次都得重新赋值

user: user-0
content: 噢，我理解了。 是select 调用之后，就会重置readfds 。 比如， 我FD_SET 了，3,4,5,6  四个文件描述符，然后调用select ,当select返回描述符4可读的时候， 3 ,5,6这三个描述符也被FD_CLR了。 如果要继续select 3,5,6 就必须再调用select之前重新FD_SET。  引用 6 楼 mymtom 的回复:int select(int nfds, fd_set *restrict readfds,        fd_set *restrict writefds, fd_set *restrict errorfds,        struct timeval *restrict timeout);  注意几个fds都是(fd_set *)类型，没有const哦，会被修改该的。  If the readfds argument is not a null pointer, it points to an object of type fd_set that on input specifies the file descriptors to be checked for being ready to read, and on output indicates which file descriptors are ready to read.  说的明白一点就是说： 调用select时，你用 readfds 告诉系统哪些描述字需要监测， select返回时，系统用 readfds 告诉你哪些描述字已经可读！ 我理解的对吧。  另外感谢 引用 3 楼 ak47_wz 的回复:1.第一个你存在的问题是因为，select中fd_set值-结果参数，并且你所关心的那一位是相同的。多个请求到达的时候，由于值-结果的缘故，只有最后一个请求保存下来了。其他覆盖掉了。所以通常我们在再次调用select函数的时候，都得再次把所有关心的字集置1. 2.第二个问题，我不太懂你的意思。FD_CLR 只是关闭那个位，并不代表那个位的空间就不存在了。另外，这也许是设计上的问题。我不太懂这个。 个人见解。 我没有很好的理解你的意思。

user: user-1
content: int select(int nfds, fd_set *restrict readfds,        fd_set *restrict writefds, fd_set *restrict errorfds,        struct timeval *restrict timeout);  注意几个fds都是(fd_set *)类型，没有const哦，会被修改该的。  If the readfds argument is not a null pointer, it points to an object of type fd_set that on input specifies the file descriptors to be checked for being ready to read, and on output indicates which file descriptors are ready to read.  说的明白一点就是说： 调用select时，你用 readfds 告诉系统哪些描述字需要监测， select返回时，系统用 readfds 告诉你哪些描述字已经可读！

user: user-2
content: 1.第一个你存在的问题是因为，select中fd_set值-结果参数，并且你所关心的那一位是相同的。多个请求到达的时候，由于值-结果的缘故，只有最后一个请求保存下来了。其他覆盖掉了。所以通常我们在再次调用select函数的时候，都得再次把所有关心的字集置1. 2.第二个问题，我不太懂你的意思。FD_CLR 只是关闭那个位，并不代表那个位的空间就不存在了。另外，这也许是设计上的问题。我不太懂这个。 个人见解。

user: user-3
content: select(nfds, readfds, writefds, exceptfds, timeout); nfds 是三个 fd_set 中最大句柄 +1 你的代码三个 fd_set 只有一个句柄 使用 nselect = select(listenfd+1, &rset, NULL, NULL, NULL); 应该就可以了

user: user-0
content: 莫非FD_SET之后，再有ISSET就会清除掉？