我的服务程序在一个客户端接入以后就开一个接收线程,负责接收它的数据。
在此期间客户机保持和服务器的连接。实际运行时,发现这个接收线程一运行,CPU利用率达到100%,根本接收不了其他的连接,请问大家怎么处理接收线程的?怎么改善接收线程的性能?
//  接收数据线程如下:
DWORD WINAPI RecvThread(LPVOID lParam)
{
  int Socket;
  Socket= (int )lParam;
  fd_set fdRead;
  struct timeval tmvTimeout={0L,100L};
  char RecvBuf[256];
 
  while (TRUE)
  {
    // 初始化
    FD_ZERO(&fdRead);
    FD_SET(Socket,&fdRead);
    int ret = select(0,&fdRead,NULL,NULL,&tmvTimeout);
    if (ret == SOCKET_ERROR)
    {
       printf("Select() Socket error: %d..\n",GetLastError ());
       continue;
    }
    else if (ret > 0)
       {  
          if (FD_ISSET(Socket,&fdRead))
           {  // 有数据可读
               nRecv= recv (Socket, RecvBuf, sizeof( RecvBuf), 0);  
               if (nRecv == SOCKET_ERROR)
                { // 读数据出错
                   printf("Recv socket error: %d..\n",GetLastError());
                 }
               else 
                if (nRecv == 0)
                { // 客户端断开连接
                      printf("remote socket closed..\n");
                      closesocket(Socket); 
                      break;                                     
                 }
                               
                // 数据读入成功,做数据处理
                printf("Successfully receive  %d bytes..\n"),nRecv); 
                ProcessData(RecvBuf); 
           } 
       }
  }
  printf("Recv thread exit with 0..\n");
  return 0;
}

解决方案 »

  1.   

    我是用whle(true),这个大循环来不停的监视客户端连接是否有数据可读的,可能是由于这个原因导致CPU利用率高的惊人。
      

  2.   

    一种方法是加sleep(1).在while里面。
    另一个方法是,是用事件方式。你的接收处理方法有问题
    if (ret == SOCKET_ERROR)
        {
           printf("Select() Socket error: %d..\n",GetLastError ());
           continue;//很显然,这里需要Getlastererro看看一下错误原因,这样,在不需要的时候,跳出循环。
        }
      

  3.   

    楼上的,请问怎么样处理select错误呢,按照您的意思。给点代码如何
      

  4.   

    我的线程加了SLEEP,cpu利用率大概20%.但是假如一个客户端需要联接很多个客户端,每个客户端对服务端的联接都使用一个线程的话,CPU的利用率就会很高。不知道能不能不用while而实现同样的功能。
      

  5.   

    我也是用While实现的,不过我只是在监听网络,代码差不多你看一下嘛,刚开始我也是CPU占用很高,后来加了一个return 就好了:
    DWORD WINAPI LoopScanThread(LPVOID lpparam)
    {
    SOCKET ListenSocket=(SOCKET)lpparam; sockaddr_in send;
    int sendlen=sizeof(send);
    CString aa2="----接收方最大允许连接数为10----";
    AfxGetMainWnd()->SendMessageToDescendants(WM_LISTBOX,(WPARAM)aa2.GetBuffer(0),1);
    aa2.ReleaseBuffer(); //接收方允许最大的连结数是10
    int rc=listen(ListenSocket,10); if(rc==SOCKET_ERROR)
    {
    CString a5="----创建监听socket失败,请检查网络后重试----";
    AfxGetMainWnd()->SendMessageToDescendants(WM_LISTBOX,(WPARAM)a5.GetBuffer(0),1);
    a5.ReleaseBuffer();
    ::MessageBeep(MB_ICONHAND);
    return 0;
    } CString aa3="----创建监听socket成功,开始监听网络----";
    AfxGetMainWnd()->SendMessageToDescendants(WM_LISTBOX,(WPARAM)aa3.GetBuffer(0),1);
    aa3.ReleaseBuffer();
    ::MessageBeep(MB_ICONASTERISK);
    while(1)
    {
    SOCKET ConnectSocket;

    ConnectSocket=accept(ListenSocket,(sockaddr*)&send,&sendlen); if(ConnectSocket==INVALID_SOCKET)
    {
    CString a="----接收发送方请求失败----";
    AfxGetMainWnd()->SendMessageToDescendants(WM_LISTBOX,(WPARAM)a.GetBuffer(0),1);
    a.ReleaseBuffer();
    ::MessageBeep(MB_ICONHAND);
    return -1;
    } CString a="----接收请求成功,连接已经建立----";
    AfxGetMainWnd()->SendMessageToDescendants(WM_LISTBOX,(WPARAM)a.GetBuffer(0),1);
    a.ReleaseBuffer();
    //直到accept()成切返回,然后进入别一个线程,来接收文件消息
    DWORD dwThread1;
    ::CreateThread(NULL,0,GetFileInfoThread,(LPVOID)ConnectSocket,0,&dwThread1);
    }
    return 0;
    }
      

  6.   

    刚刚觉得用SETTIMER來做,不用while循环。不知道cpu会不会降低一点。来做个测试。
      

  7.   

    BOOL CClientOverlappedSock::OnRead()
    {
    if(!IsConnected())
    return false;
    DWORD dwTransbit = 0;
    DWORD Resv = 0;
    DWORD dwFlag = 0;
    WSABUF buffer;
    BOOL bQuery = false;
    int state = 0;

    bQuery = WSAGetOverlappedResult( m_RecSocket, &ConnectedSocketOverlapped,
    &dwTransbit,false,&dwFlag);
    if(bQuery)
    {
    if(dwTransbit == 0)
    {
    OnClose();
    return true;
    }
    while(1)
    {
    if( rPag.len - sizeof(PAG) ==  DataRes)
    {
    ////
    Work();
    Reset();
    ////

    buffer.buf = (char*)& rPag;
    buffer.len = sizeof(PAG);
    state = WSARecv( m_RecSocket,&buffer,1,&Resv,
    &dwFlag, &ConnectedSocketOverlapped,NULL);

    if(state == 0)
    {
    continue;
    }else
    {
    DWORD err = WSAGetLastError();
    if(err != WSA_IO_PENDING)
    {
    TRACE1("erro code1 %d\n",err);
    OnClose();
    return false;
    }else
    {
    if(ERROR_IO_PENDING == err)
    {
    return true;
    }
    }
    }
    }else
    if( rPag.len - sizeof(PAG) -  DataRes > 0)
    {
    if(!m_bReadPending)
    {
    if(buff == NULL)
    {
    buff = new char [ rPag.len - sizeof(PAG)];
    memset( buff,0, rPag.len - sizeof(PAG));
    buffer.buf =  buff;
    buffer.len = rPag.len - sizeof(PAG); 
    } Resv = 0;
    buffer.len = rPag.len - sizeof(PAG) -  DataRes; 
    buffer.buf =  buff +  DataRes;
    state = WSARecv( m_RecSocket,&buffer,1,&Resv,
    &dwFlag, &ConnectedSocketOverlapped,NULL);
    if(state == 0)
    {
    DataRes+=Resv;
    continue;
    }else
    {
    DWORD err = WSAGetLastError();
    if(err != WSA_IO_PENDING)
    {
    TRACE1("erro code2 %d\n",err);
    OnClose();
    return false;
    }else
    {
    if(ERROR_IO_PENDING == err)
    {
    m_bReadPending = true;
    return true;
    }
    }
    }
    }else
    {
    DataRes+=dwTransbit;
    }
    }
    if(!IsConnected())
    return 0;
    Sleep(1);
    TRACE1("RES DATA IS %u\n",DataRes);
    }
    }else
    {
    DWORD err = WSAGetLastError();
    if(err != ERROR_IO_INCOMPLETE)
    {
    OnClose();
    TRACE1("erro code3 %d\n",err);
    return false;
    }else
    return true;
    }
    return true;
    }
    吐血回贴!
    当没有数据来时,根本不占用cpu.
      

  8.   

    加SLEEP( )控制
    或者用消息EVENT通知。
    WHILE( )
    循环对CPU的消耗太巨大了,一定要有措施来主动交出CPU时间段