fd_set fdSocket;
FD_ZERO(&fdSocket);
FD_SET(sListen,&fdSocket);
while (true)
{
fd_set fdRead=fdSocket;
int nRet=select(0,&fdRead,NULL,NULL,NULL);
if (nRet>0)
{
for (int i=0;i<(int)fdSocket.fd_count;i++)
{
if (FD_ISSET(fdSocket.fd_array[i],&fdRead))
{
char szText[256];
int nRecv=recv(fdSocket.fd_array[i],szText,256,0);
if (nRecv>0)                              
{
szText[nRecv]='\0';
cout<<"接收到数据:"<<szText<<endl;
}
else                                       
{
closesocket(fdSocket.fd_array[i]);
FD_CLR(fdSocket.fd_array[i],&fdSocket);
}
}
}
}
else
{
cout<<"Select执行失败!\n";
break;
}
}
这段代码在for (int i=0;i<(int)fdSocket.fd_count;i++)这个for循环体内,又会调用FD_CLR去改变fdSocket,这样是不是有问题呀,我觉得这样有可能会跳过一些套接字。举个例子,i = 0时,fdSocket里面有1,2,3,4,5。
如果他删掉了1,再次进入循环时fdSocket.fd_count变成4了,而i变成1了,fdSocket里剩下2,3,4,5。
这样,岂不就跳过了2,直接判断3了???请大家指教,谢谢!

解决方案 »

  1.   

    顺便问一下,如果我的判断是对的,那么如何调用FD_CLR才是对的,谢谢大家!
      

  2.   

    你用SELECT模型要设置第5个参数,那是时间参数,不然你用SELECT模型就没有意义了
      

  3.   

    这里有问题,FD_CLR是删除一个套接字,但是删除后循环仍在继续,就会出错。
    其实在循环内部不用FD_CLR,应该在for (int i=0;i<(int)fdSocket.fd_count;i++)循环结束后一次性FD_ZERO,然后还得再一遍FD_SET。
      

  4.   


    那请问如何在fdSocket中保存住有效的套接字呢?不用FD_CLR的话,下次循环fdSocket里面就会有失效的套接字了...
      

  5.   


    谢谢,我这个socket是长连接,select不限时的.
      

  6.   

    这么写:fd_set fdRead=fdSocket;
    int nRet=select(0,&fdRead,NULL,NULL,NULL);
    if (nRet>0)
    {
    for (int i=0;i<(int)fdRead.fd_count;i++)
    { char szText[256];
    int nRecv=recv(fdRead.fd_array[i],szText,256,0);
    if (nRecv>0)                              
    {
    szText[nRecv]='\0';
    cout<<"接收到数据:"<<szText<<endl;
    }
    else                                       
    {
    FD_CLR(fdRead.fd_array[i],&fdSocket);
                            closesocket(fdRead.fd_array[i]);
    }
    }
    }
      

  7.   


    下次循环之前也就是 for (int i=0;i<(int)fdSocket.fd_count;i++)循环结束后FD_ZERO一下,再FD_SET一下。
      

  8.   

    遍历完socket,并处理完成后,一次性清除FD_ZERO,然后再把有效的socket选进去即可
      

  9.   


    兄弟,这个closesocket和fd_clr的先后顺序应该没问题的吧。
      

  10.   


    支持!收不到就表示该SOCKET已经退出了!
      

  11.   


    fd_set fdSocket;
    FD_ZERO(&fdSocket);
    FD_SET(&fdSocket, sListen);while(TRUE)
    {
     fd_set fdRead = fdSocket;
     int nRet = select(0, &fdRead, NULL, NULL, NULL);
     if(nRet > 0)
     {
      for(int i=0; i<(int)fd_Socket.fd_count; i++)
      {
       if(FD_ISSET(fdSocket.fd_array[i], &fdRead)
       {
         if(sListen == fdSocket.fd_array[i])
         {
           if(fdSocket.fd_count < FD_SETSIZE)
           {
              SOCKADDR_IN remote;
              int len = sizeof(remote);
              SOCKET sNew = accept(sListen, (LPSOCKADDR)&remote, &len);
              FD_SET(sNew, &fdSocket);
           }
           else
           {
             // Too much client
             continue;
           }
         }
         else
         {
           char szText[256] = {0};
           int nRecv = recv(fdSocket.fd_array[i], sztext, 256, 0);
           if(nRecv > 0)
           {
             // print recv data
           }
           else
           {
             closesocket(fdSocket.fd_array[i]);
             FD_CLR(fdSocket.fd_array[i], &fdSocket);
           }
         }
       }
      }
     }
     else
     {
      // select errror;
      break;
     }
    }
      

  12.   


    不好意思,我怎么还是觉得这样写会有bug,就想我在帖子描述中提问的那样...
      

  13.   


    vector<int> bb;
    bb.push_back(0);
    bb.push_back(1);
    bb.push_back(2);
    bb.push_back(3);
    bb.push_back(4); vector<int>::const_iterator begin; for (begin = bb.begin(); begin != bb.end(); ++begin)
    {
    cout << *begin << endl; if (*begin == 2)
    begin = bb.erase(begin);
    }
    就像这段代码一样,只能输出0,1,2,4,而3被跳过去了...
      

  14.   

    说明你只会看书,不注意实践 哈哈
    select函数的作用要明白,函数返回后fdRead里就全部是可读的套接字了(不可读的会被清除出数组)
    所以for轮询fdRead,接收下数据就可以,不需要轮询fdSocket并用FD_ISSET这个判断了的
    套接字关闭后也是可读的,这时读到返回是0罢了,这时先从fdSocket清除这个socket值然后再closesocket就可以了,下次再select,从新把fdSocket赋值给fdRead即可。
      

  15.   


    呃,兄弟,我明白了,有一个地方我之前看走眼了。
    可否指教一下,11楼的代码是否像我分析的那样,有bug,因为他for循环直接用fdSocket判断的,而不是像你的代码,用fdRead判断的,这样可能会漏泄某些套接字吧。
      

  16.   

    fd_set fdSocket;
    FD_ZERO(&fdSocket);
    FD_SET(&fdSocket, sListen);while(TRUE)
    {
     fd_set fdRead = fdSocket;
     int nRet = select(0, &fdRead, NULL, NULL, NULL);
     if(nRet > 0)
     {
      for(int i=0; i<(int)fd_Socket.fd_count; i++)
      {
       if(FD_ISSET(fdSocket.fd_array[i], &fdRead)
       {
           char szText[256] = {0};
           int nRecv = recv(fdSocket.fd_array[i], sztext, 256, 0);
           if(nRecv > 0)
           {
             // print recv data
           }
           else
           {
             closesocket(fdSocket.fd_array[i]);
             FD_CLR(fdSocket.fd_array[i], &fdSocket);
           }
       }
     }
    }
    我还是觉得有问题啊,假如fd_Socket里有socket1,2,3,4,5。
    而select一次后,fdRead里剩下socket1,2,3。
    第一次循环的时候,i = 0,recv socket1的时候,得到的结果是0,那么socket1就从fd_Socket里面去掉了。
    第二次循环的时候,i = 1,fd_Socket里面剩下socket2,3,4,5。这样fdSocket.fd_array[i]就变成socket3了,那么socket2不就被跳过了吗?求解释...
      

  17.   

    fd_set fdRead = fdSocket;
     int nRet = select(0, &fdRead, NULL, NULL, NULL);
     这2个代码,为什么这边需要进行个赋值呢。把fdSocket 给了fdRead,然后select 的是fdread呢?
    select 后,fdread里面永远是可以使用的,那些不能使用的就不会在fdread里面呢
    而且在select结束后和再一次select前 fdread的里面的是没有变化的,永远是上一次select的结果。不知道是否能否符合你的意思
      

  18.   


    因为在select内部还可能调用FD_SET向fdSocket里面新增套接字。
      

  19.   

    本帖最后由 VisualEleven 于 2010-09-29 13:59:24 编辑
      

  20.   


    说的没错,正是因为这个原因,所以我认为有Bug的代码一次For循环中如果调用了FD_CLR,那么会跳过下一个套接字,这也是我对11楼代码及楼顶代码的疑问所在。我想,由于套了while循环,所以它可以正常工作,因为被跳过的套接字下一次进入while循环的时候还是会被处理。但单从一次for循环的开始到结束来看,我认为那一小段代码的逻辑就是有问题的。不知道理解的对不对,求鉴定!
      

  21.   


      vector<int> bb;
        bb.push_back(0);
        bb.push_back(1);
        bb.push_back(2);
        bb.push_back(3);
        bb.push_back(4);    vector<int>::const_iterator begin= bb.begin();    for (; begin != bb.end();)
        {
            cout << *begin << endl;        if (*begin == 2)
                begin = bb.erase(begin);
            else
                ++begin;
        }
      

  22.   

    void Test()
    {
    fd_set fdSocket;
    FD_ZERO(&fdSocket);
    FD_SET(1, &fdSocket);
    FD_SET(2, &fdSocket);
    FD_SET(3, &fdSocket);
    FD_SET(4, &fdSocket);
    for (int i = 0; i < (int)fdSocket.fd_count;)
    {
    printf("%d ", fdSocket.fd_array[i]);
    if (fdSocket.fd_array[i] == 2)
    FD_CLR(fdSocket.fd_array[i], &fdSocket);
    else
    i++;
    }
    }