一个线程池程序,转发客户端请求到web服务器,程序接受客户端连接,有个clientsocket,然后转发到web服务器有个serversocket,我在serversocket做了个池,思路是程序启动时先建一些,并置状态为未用,当有客户端请求来时建立线程取一个未用serversocket,在打开若干页面时不会断开,但多打开几个却会自动断开,再打网页就打不开了,我监听了池内每个socket的FD_CLOSE事件,然后重新连接,但是还不行,而不用线程池的话就没问题,和用线程池没有本质的区别啊,只是数组保存下,再取出来,哪位哥们有过这种处理经验啊 给指点下 我把关键代码贴出了,能解决马上给分!

解决方案 »

  1.   

         printf("正在与服务器连接....\n"); 
         threadPool->GetServerSocketPool(); //这里主线程取得socket池部分,不用池就注掉这里
         printf("正在接受客户端连接....\n"); 
    bool CThreadPoolManage::GetServerSocketPool()
    {
       SOCKET ServerSocket=0; 
       if (serverSocketList.size()==0)
       {
       HANDLE handle = NULL;
       DWORD id = 0;
       serverSocketStruct socketStruct;
       for(int i=0;i<SOCKETNUM;i++)
       {
              ServerSocket=ConnectHost();
      socketStruct.server=ServerSocket;
      socketStruct.reconnected=true;
      wsaevent[i]= WSACreateEvent();
      int iKeepAlive=-1;
              int iOptLen = sizeof(iKeepAlive);
              if (getsockopt(ServerSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, &iOptLen) == SOCKET_ERROR)
      {
                cout << "getsockopt failed. error code = " << WSAGetLastError() << endl;
      }
              else
      {
    iKeepAlive = 1;
    //这里设置成功的Keep Alive是针对操作系统的所有网络通信 
    if (setsockopt(ServerSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, iOptLen) == SOCKET_ERROR)
    {
    cout << "setsockopt failed. error code = " << WSAGetLastError() << endl;
    }
     else
    {
    iKeepAlive = -1;
    if (getsockopt(ServerSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, &iOptLen) == SOCKET_ERROR)
    {
    cout << "getsockopt failed. error code = " << WSAGetLastError() << endl;
    }
    else if (iKeepAlive == 1)
    {    // GetQueuedCompletionStatus();
    TCP_KEEPALIVE inKeepAlive = {0};
    unsigned long ulInLen = sizeof(TCP_KEEPALIVE);
    TCP_KEEPALIVE outKeepAlive = {0};
    unsigned long ulOutLen = sizeof(TCP_KEEPALIVE);
                        unsigned long ulBytesReturn=0;
    //设置socket的keep alive为10秒,并且发送次数为3次 
    inKeepAlive.onoff = 1;
    inKeepAlive.keepaliveinterval = 5;
    inKeepAlive.keepalivetime = 3;
    //为选定的SOCKET设置Keep Alive,成功后SOCKET可通过Keep Alive自动检测连接是否断开 
    if (WSAIoctl(ServerSocket, SIO_KEEPALIVE_VALS, 
    (LPVOID)&inKeepAlive, ulInLen, 
    (LPVOID)&outKeepAlive, ulOutLen, 
    &ulBytesReturn, NULL, NULL) == SOCKET_ERROR)
    {
    cout << "WSAIoctl failed. error code = " << WSAGetLastError() << endl;
    }
    }
     
      if (SOCKET_ERROR==WSAEventSelect(ServerSocket,wsaevent[i], FD_CLOSE))
      {
                  i--;
      closesocket(ServerSocket);
      WSACloseEvent(wsaevent[i]); 
      continue;
      }
      socketStruct.used=false; 
      serverSocketList.push_back(socketStruct);
       }
          // CreateThread(NULL,NULL,WSAWaitForMultipleEventsThread,(LPVOID)(serverSocketList.size()),0,&id);
          //SetEvent(m_HEvent);
       }
       return true;
    }
    有任务就 
         threadPool->AddMission(workThread);从线程池找出空闲线程开始
    往下执行  这个是线程函数
    int WorkerThread::PortTransfer()
    {
        SOCKET ServerSock;
        //先连接到目标计算机的服务
    //    ServerSock =threadPool->GetServerSocket(this->socketIndex);去socket池socket
        ServerSock=threadPool->ConnectHost();这个没有问题
         if(ServerSock <= 0)
         {
             closesocket(this->ClientSocket);
             return 0;
         }
         SOCKINFO socks;
         socks.ClientSock = this->ClientSocket;//客户的套接字
         socks.ServerSock = ServerSock;//目标计算机服务的套接字
         //进入纯数据转发状态
         return TransmitData((LPVOID)&socks);
    }DWORD WINAPI WorkerThread::TransmitData(LPVOID lParam)//在两个SOCKET中进行数据转发
    {
         SOCKINFO socks = *((SOCKINFO*)lParam);
         SOCKET ClientSock = socks.ClientSock;
         SOCKET ServerSock = socks.ServerSock;
         char RecvBuf[MAXBUFSIZE] = {0};
         fd_set Fd_Read;
         int ret, nRecv;     while(1)
         {   ::EnterCriticalSection(&section);  
             FD_ZERO(&Fd_Read);
             FD_SET(ClientSock, &Fd_Read);
             FD_SET(ServerSock, &Fd_Read);
             ret = select(FD_SETSIZE, &Fd_Read, NULL, NULL, NULL);
             if(ret <= 0)  
               goto error;
             if(FD_ISSET(ClientSock, &Fd_Read))
             {
                 nRecv = recv(ClientSock, RecvBuf, sizeof(RecvBuf), 0);
                 if(nRecv <= 0)
                 goto error;
                 ret = DataSend(ServerSock, RecvBuf, nRecv);
                 if(ret == 0 || ret != nRecv)
                 goto error;
             }
             if(FD_ISSET(ServerSock, &Fd_Read))
             {
                 nRecv = recv(ServerSock, RecvBuf, sizeof(RecvBuf), 0);
                 int a=WSAGetLastError();
                 if(nRecv <= 0)
                 goto error;
                 ret = DataSend(ClientSock, RecvBuf, nRecv); 
                 if(ret == 0 || ret != nRecv)
                 goto error;
             }
            ::LeaveCriticalSection(&section); 
         }     error:     
     ::EnterCriticalSection(&errorsection);
         closesocket(ClientSock);
         if (NULL!=threadPool) 
         {
    //         threadPool->serverSocketList[socketIndex].used=false; 这里是socket池部分,如果出错就置标志位 重新连接
    //  threadPool->serverSocketList[socketIndex].reconnected=false;
             threadPool->socketList.push_back(ServerSock);不用socket池的话,收集serverscoket定时销毁重建 
         }
     ::LeaveCriticalSection(&errorsection); 
         return 0;
    }
      

  2.   

    用keepalive的话也不可以啊 它只是检测有没有断开 没有说怎么重连啊
      

  3.   

    怎么做?能给个代码吗?和keepalive有什么不同呢?
      

  4.   

    我现在也在看iocp模型,好像有点麻烦
      

  5.   

    不用线程池,你这个服务器太脆弱,经不起大量的并发连接,重新连接应该让客户端去做,服务端采用IOCP,可伸缩性比较高,但要考虑的问题也是相当多,建议阅读网上开源IOCP
      

  6.   

    定时发送包检测能保持socket连接吗?
      

  7.   

    定时发送包检测能保持socket连接吗?