什么原因?
上代码:
//////////////////////////////////////////////////////
// select.cpp文件
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "WS2_32")    // 链接到WS2_32.libclass InitWinSock
{
public:
    InitWinSock(BYTE minorVer = 2, BYTE majorVer = 2)
    {
        // 初始化WS2_32.dll
        WSADATA wsaData;
        WORD sockVersion = MAKEWORD(minorVer, majorVer);
        if(::WSAStartup(sockVersion, &wsaData) != 0)
        {
            exit(0);
        }
    }
    ~InitWinSock()
    {
        ::WSACleanup();
    }
};
#include <windows.h>
#include <process.h>
InitWinSock theSock;FD_SET g_fdRead;FD_SET g_allSet;        //全集SOCKET g_sListen;unsigned long _stdcall ThreadFun(void*)
{
    while(1)
    {        g_fdRead=g_allSet;        timeval  timeval;        timeval.tv_sec=0;
        timeval.tv_usec=0;        int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval);        printf("%d\n",nRet);        if(nRet<=0)
        {
            Sleep(500);
            continue;
        }        //检测是否有新连接,或者有数据传输
        if(FD_ISSET(g_sListen,&g_allSet))
        {
            SOCKET stmp=NULL;
            sockaddr_in sockadd;
            int nLen=sizeof(sockaddr_in);            stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen);            FD_SET(stmp,&g_allSet);        }//可以运行到for 循环中!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        for(int i=0;i< g_fdRead.fd_count;i++)
        {            if(FD_ISSET(g_fdRead.fd_array[i],&g_allSet))
            {                SOCKET stmp=NULL;
                sockaddr_in sockadd;
                int nLen=sizeof(sockaddr_in);
                char buf[200];
                ZeroMemory(buf,sizeof(buf));
                recv(g_fdRead.fd_array[i],buf,sizeof(buf),0);                printf("接受数据为:%s\n",buf);
            }
                }
        Sleep(500);    } //end while
    return 0;}
int main()
{
        USHORT nPort = 9585; // 此服务器监听的端口号    // 创建监听套节字
    g_sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(nPort);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    // 绑定套节字到本地机器
    if(::bind(g_sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf(" Failed bind() \n");
        return -1;
    }
    // 进入监听模式
    ::listen(g_sListen, 5);    FD_ZERO(&g_allSet);    FD_ZERO(&g_fdRead);
    FD_SET(g_sListen,&g_allSet);    // HANDLE hThread=(HANDLE)_beginthreadex(NULL,0,ThreadFun,NULL,0,NULL);    HANDLE hThread=CreateThread(NULL,0,ThreadFun,0,0,NULL);    WaitForSingleObject(hThread,-1);    CloseHandle(hThread);    return 0;
}问题代码中已经说了for循环是可以进入的,数据就是接受的为空!当只有一个客户端和服务端通信啊,且已经连接上了,
执行了for循环后,没有收到数据(这是第一个问题)
for 循环后,再次进入外层的while循环,此时还会会进入这个if块。if(FD_ISSET(g_sListen,&g_allSet))
   {
   SOCKET stmp=NULL;
   sockaddr_in sockadd;
   int nLen=sizeof(sockaddr_in);   stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen);   FD_SET(stmp,&g_allSet);   }
这个if块是用来检测有新的客户端连接的,  已经连接上了,为什么还会进入? 进入就堵死了。到底是怎么回事啊?

解决方案 »

  1.   

      int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval);这句话堵死了函数最后一个参数timeval,如果是NULL(也就是0)就是堵死
      

  2.   

    亲,你说的肯定不对,NULL和那个结构体的字段设置为0,不一样的,如果是NULL,运行到select哪里就会堵死,下面的代码根本不能执行for循环更是不可能了。你记忆有误。我现在贴一段修改的代码:  timeval.tv_sec=1;
            timeval.tv_usec=500;        int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval);        printf("%d\n",nRet);        if(nRet<=0)
            {
                Sleep(500);
                continue;
            }        //检测是否有新连接,或者有数据传输
            if(FD_ISSET(g_sListen,&g_allSet))
            {
                SOCKET stmp=NULL;
                sockaddr_in sockadd;
                int nLen=sizeof(sockaddr_in);            stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen);            FD_SET(stmp,&g_allSet);        }依然是有问题的,问题一个个的解决吧请你耐心看,麻烦你了啊。1. 我们不说接受数据的问题,只谈accept新连接的问题。这个代码有个逻辑的错误。
    假设有个新的连接连接服务器,那么则accept成功(for 循环暂且无视它吧)sleep后,第二次进入while循环了。此时fd_allset中是有g_sListen监听套接字的。导致 FD_SET是成功的,         msdn有云:该宏是检测 某个套接字是否在集合中。所以导致进入了if语句,此时到了accept,由于没有新的连接accept堵死了。       
    结论:非堵塞模型的 select的acccept其实是堵塞函数。想一想也对,如果是非堵塞的话,正常连接,accept的返回值恐怕值得考虑,深思。
    如何修改这个问题呢?
    (1)去掉FD-SET判断? 怕是去掉也解决不了问题。(2)用FD_SET(g_sListen,fd_read) 替代 FD-SET(g_sListen,g_allset)更是解决不了问题
      

  3.   

    晕啊, mfc 板块人气越来越少了
      

  4.   

    亲们,我又发现个问题 int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval);        printf("%d\n",nRet);        if(nRet<=0)
            {
                Sleep(500);
                continue;
            }
    看到printft了吧
    我只运行服务端,客户端不运行
    是可以看到打印的结果的,说明,select是非堵塞
    但是隔几分钟后,发现不会打印了,什么原因呢( 我没有开启客户端)
    ?为什么刚开始 没开启,可以打印,隔几分钟后还不开启,就不打印了??
      

  5.   

    你觉得我说的不对?我无语了啊,要我贴MSDN给你看么?
      

  6.   

    timeout [in] 
    The maximum time for select to wait, provided in the form of a TIMEVAL structure. Set the timeout parameter to null for blocking operations.
    亲,你看还有你结合 2 L的代码,时间已经改了依然有问题。所以这个时间或许有问题,但不是程序致命的问题。
      

  7.   

    完整代码:#include <stdio.h>
    #include <winsock2.h>
    #pragma comment(lib, "WS2_32")    // 链接到WS2_32.libclass InitWinSock
    {
    public:
        InitWinSock(BYTE minorVer = 2, BYTE majorVer = 2)
        {
            // 初始化WS2_32.dll
            WSADATA wsaData;
            WORD sockVersion = MAKEWORD(minorVer, majorVer);
            if(::WSAStartup(sockVersion, &wsaData) != 0)
            {
                exit(0);
            }
        }
        ~InitWinSock()
        {
            ::WSACleanup();
        }
    };
    #include <windows.h>
    #include <process.h>
    InitWinSock theSock;FD_SET g_fdRead;FD_SET g_allSet;        //全集SOCKET g_sListen;unsigned long _stdcall ThreadFun(void*)
    {
        while(1)
        {        g_fdRead=g_allSet;        timeval  timeval;
            timeval.tv_sec=1;
            timeval.tv_usec=500;        int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval);        printf("%d\n",nRet);        if(nRet<=0)
            {            Sleep(500);
                continue;
            }        //检测是否有新连接,或者有数据传输
            if(FD_ISSET(g_sListen,&g_allSet))
            {
                SOCKET stmp=NULL;
                sockaddr_in sockadd;
                int nLen=sizeof(sockaddr_in);            stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen);            FD_SET(stmp,&g_allSet);        }//可以运行到for 循环中!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            for(int i=0;i< g_fdRead.fd_count;i++)
            {            if(FD_ISSET(g_fdRead.fd_array[i],&g_allSet))
                {                SOCKET stmp=NULL;
                    sockaddr_in sockadd;
                    int nLen=sizeof(sockaddr_in);
                    char buf[200];
                    ZeroMemory(buf,sizeof(buf));
                    recv(g_fdRead.fd_array[i],buf,sizeof(buf),0); int sdggssdgsd=1;                //printf("接受数据为:%s\n",buf);
                }
                    }
            Sleep(500);    } //end while
        return 0;}
    int main()
    {
            USHORT nPort = 9585; // 此服务器监听的端口号    // 创建监听套节字
        g_sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_port = htons(nPort);
        sin.sin_addr.S_un.S_addr = INADDR_ANY;
        // 绑定套节字到本地机器
        if(::bind(g_sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
        {
            printf(" Failed bind() \n");
            return -1;
        }
        // 进入监听模式
        ::listen(g_sListen, 5);    FD_ZERO(&g_allSet);    FD_ZERO(&g_fdRead);
        FD_SET(g_sListen,&g_allSet);    // HANDLE hThread=(HANDLE)_beginthreadex(NULL,0,ThreadFun,NULL,0,NULL);    HANDLE hThread=CreateThread(NULL,0,ThreadFun,0,0,NULL);    WaitForSingleObject(hThread,-1);    CloseHandle(hThread);    return 0;
    }1. 当没有客户单连接 的时候,开始程序不会堵塞,会调用printf结果运行几分钟后就会堵塞2. 如果有客户单连接,接收不到数据
      

  8.   

    int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval);我好像记得select的第一个参数是最大数加1,你这里的为什么是0。windows 下的编程我了解比较少,不过应该也差不多吧。建议好好看看select的用法。
      

  9.   

    你这代码问题一大堆,用select模型还用sleep?
      

  10.   

    虽然没解决问题, 感谢2位纠正一个问题
    "当没有客户单连接 的时候,开始程序不会堵塞,会调用printf结果运行几分钟后就会堵塞"这个说法不对!!!!!我看错了,但是:接收不到数据 这个问题一直没有解决掉。还有只要和客户端连接了,然后 运行几次后,就会死在accept那里!!!!
      

  11.   

    等你上了客户端代码。、
    还有
    while(1)

    g_fdRead=g_allSet;  //这啥?
    换成这个 FD_ZERO(&g_fdRead);
      

  12.   

    太感谢你了, 周末劳累你回复这么多,服务端致命的地方就是这里。代码是从书本抄的。坑人啊
    接受的问题,我猜测是客户端导致的问题:
    我发代码:以下是客户端//////////////////////////////////////////////////////////
    // TCPClient.cpp文件
    #include "common/InitSock.h"
    #include <stdio.h>
    CInitSock initSock; // 初始化Winsock库int main()
    {
    // 创建套节字
    SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(s == INVALID_SOCKET)
    {
    printf(" Failed socket() \n");
    return 0;
    }

    // 也可以在这里调用bind函数绑定一个本地地址
    // 否则系统将会自动安排

    // 填写远程地址信息
    sockaddr_in servAddr; 
    servAddr.sin_family = AF_INET;
    servAddr.sin_port = htons(9585);
    // 注意,这里要填写服务器程序(TCPServer程序)所在机器的IP地址
    // 如果你的计算机没有联网,直接使用127.0.0.1即可
    servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)
    {
    printf(" Failed connect() \n");
    return 0;
    }
    else
    {
    printf(" Success connect() \n");
    }
    char buf[100];
    memset(buf,0,100); strcpy(buf,"hello"); while(1)
    {
    send(s,buf,100,0);

    Sleep(1000); }
    // 关闭套节字
    ::closesocket(s);
    return 0;
    }
    刚才我这里断网,不好意思啊,前辈
      

  13.   

    回复楼上:当服务端和一个客户端连接时候,又和另一个客户端连接,导致堵塞的问题
    已经解决了现在剩下最后一个问题:接受数据为空!!!!buf的内容始终是""可以进入for循环
      

  14.   

    <windows网络编程技术>第8章有样例代码:
    // Module Name: select.cpp
    //
    // Description:
    //
    //    This sample illustrates how to develop a simple echo server Winsock
    //    application using the select() API I/O model. This sample is
    //    implemented as a console-style application and simply prints
    //    messages when connections are established and removed from the server.
    //    The application listens for TCP connections on port 5150 and accepts
    //    them as they arrive. When this application receives data from a client,
    //    it simply echos (this is why we call it an echo server) the data back in
    //    it's original form until the client closes the connection.
    //
    // Compile:
    //
    //    cl -o select select.cpp ws2_32.lib
    //
    // Command Line Options:
    //
    //    select.exe 
    //
    //    Note: There are no command line options for this sample.
    //
    #include <winsock2.h>
    #include <windows.h>
    #include <stdio.h>#define PORT 5150
    #define DATA_BUFSIZE 8192typedef struct _SOCKET_INFORMATION {
       CHAR Buffer[DATA_BUFSIZE];
       WSABUF DataBuf;
       SOCKET Socket;
       OVERLAPPED Overlapped;
       DWORD BytesSEND;
       DWORD BytesRECV;
    } SOCKET_INFORMATION, * LPSOCKET_INFORMATION;BOOL CreateSocketInformation(SOCKET s);
    void FreeSocketInformation(DWORD Index);DWORD TotalSockets = 0;
    LPSOCKET_INFORMATION SocketArray[FD_SETSIZE];void main(void)
    {
       SOCKET ListenSocket;
       SOCKET AcceptSocket;
       SOCKADDR_IN InternetAddr;
       WSADATA wsaData;
       INT Ret;
       FD_SET WriteSet;
       FD_SET ReadSet;
       DWORD i;
       DWORD Total;
       ULONG NonBlock;
       DWORD Flags;
       DWORD SendBytes;
       DWORD RecvBytes;
       if ((Ret = WSAStartup(0x0202,&wsaData)) != 0)
       {
          printf("WSAStartup() failed with error %d\n", Ret);
          WSACleanup();
          return;
       }   // Prepare a socket to listen for connections.   if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
          WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) 
       {
          printf("WSASocket() failed with error %d\n", WSAGetLastError());
          return;
       }   InternetAddr.sin_family = AF_INET;
       InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
       InternetAddr.sin_port = htons(PORT);   if (bind(ListenSocket, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr))
          == SOCKET_ERROR)
       {
          printf("bind() failed with error %d\n", WSAGetLastError());
          return;
       }   if (listen(ListenSocket, 5))
       {
          printf("listen() failed with error %d\n", WSAGetLastError());
          return;
       }   // Change the socket mode on the listening socket from blocking to
       // non-block so the application will not block waiting for requests.   NonBlock = 1;
       if (ioctlsocket(ListenSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
       {
          printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
          return;
       }   while(TRUE)
       {
          // Prepare the Read and Write socket sets for network I/O notification.
          FD_ZERO(&ReadSet);
          FD_ZERO(&WriteSet);      // Always look for connection attempts.      FD_SET(ListenSocket, &ReadSet);      // Set Read and Write notification for each socket based on the
          // current state the buffer.  If there is data remaining in the
          // buffer then set the Write set otherwise the Read set.      for (i = 0; i < TotalSockets; i++)
             if (SocketArray[i]->BytesRECV > SocketArray[i]->BytesSEND)
                FD_SET(SocketArray[i]->Socket, &WriteSet);
             else
                FD_SET(SocketArray[i]->Socket, &ReadSet);      if ((Total = select(0, &ReadSet, &WriteSet, NULL, NULL)) == SOCKET_ERROR)
          {
             printf("select() returned with error %d\n", WSAGetLastError());
             return;
          }      // Check for arriving connections on the listening socket.
          if (FD_ISSET(ListenSocket, &ReadSet))
          {
             Total--;
             if ((AcceptSocket = accept(ListenSocket, NULL, NULL)) != INVALID_SOCKET)
             {            // Set the accepted socket to non-blocking mode so the server will
                // not get caught in a blocked condition on WSASends            NonBlock = 1;
                if (ioctlsocket(AcceptSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
                {
                   printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
                   return;
                }            if (CreateSocketInformation(AcceptSocket) == FALSE)
                   return;         }
             else
             {
                if (WSAGetLastError() != WSAEWOULDBLOCK)
                {
                   printf("accept() failed with error %d\n", WSAGetLastError());
                   return;
                }
             }
          }      // Check each socket for Read and Write notification until the number
          // of sockets in Total is satisfied.      for (i = 0; Total > 0 && i < TotalSockets; i++)
          {
             LPSOCKET_INFORMATION SocketInfo = SocketArray[i];         // If the ReadSet is ed for this socket then this means data
             // is available to be read on the socket.         if (FD_ISSET(SocketInfo->Socket, &ReadSet))
             {
                Total--;            SocketInfo->DataBuf.buf = SocketInfo->Buffer;
                SocketInfo->DataBuf.len = DATA_BUFSIZE;            Flags = 0;
                if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes,
                   &Flags, NULL, NULL) == SOCKET_ERROR)
                {
                   if (WSAGetLastError() != WSAEWOULDBLOCK)
                   {
                      printf("WSARecv() failed with error %d\n", WSAGetLastError());                  FreeSocketInformation(i);
                   }               continue;
                } 
                else
                {
                   SocketInfo->BytesRECV = RecvBytes;               // If zero bytes are received, this indicates the peer closed the
                   // connection.
                   if (RecvBytes == 0)
                   {
                      FreeSocketInformation(i);
                      continue;
                   }
                }
             }
             // If the WriteSet is ed on this socket then this means the internal
             // data buffers are available for more data.         if (FD_ISSET(SocketInfo->Socket, &WriteSet))
             {
                Total--;            SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->BytesSEND;
                SocketInfo->DataBuf.len = SocketInfo->BytesRECV - SocketInfo->BytesSEND;            if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &SendBytes, 0,
                   NULL, NULL) == SOCKET_ERROR)
                {
                   if (WSAGetLastError() != WSAEWOULDBLOCK)
                   {
                      printf("WSASend() failed with error %d\n", WSAGetLastError());                  FreeSocketInformation(i);
                   }               continue;
                }
                else
                {
                   SocketInfo->BytesSEND += SendBytes;               if (SocketInfo->BytesSEND == SocketInfo->BytesRECV)
                   {
                      SocketInfo->BytesSEND = 0;
                      SocketInfo->BytesRECV = 0;
                   }
                }
             }
          }
       }
    }BOOL CreateSocketInformation(SOCKET s)
    {
       LPSOCKET_INFORMATION SI;
          
       printf("Accepted socket number %d\n", s);   if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,
          sizeof(SOCKET_INFORMATION))) == NULL)
       {
          printf("GlobalAlloc() failed with error %d\n", GetLastError());
          return FALSE;
       }   // Prepare SocketInfo structure for use.   SI->Socket = s;
       SI->BytesSEND = 0;
       SI->BytesRECV = 0;   SocketArray[TotalSockets] = SI;   TotalSockets++;   return(TRUE);
    }void FreeSocketInformation(DWORD Index)
    {
       LPSOCKET_INFORMATION SI = SocketArray[Index];
       DWORD i;   closesocket(SI->Socket);   printf("Closing socket number %d\n", SI->Socket);   GlobalFree(SI);   // Squash the socket array   for (i = Index; i < TotalSockets; i++)
       {
          SocketArray[i] = SocketArray[i + 1];
       }   TotalSockets--;
    }