2009-12-02 63 views
1

调用此函数以在新线程中为每个客户端提供服务。在消费函数中,这些档案被读取和写入,但函数在客户端完成读取所有响应之前返回,以便套接字超出范围并关闭,从而在客户端中创建异常。我假设在CArchive上的任何写入都应该阻塞,直到在客户端读取它为止。我在这里做出错误的假设吗? 如果我在超出范围(尝试)之前添加延迟(这不是一种好方法),代码工作正常,我不知道在阻止所有数据传输之前是否有任何方法阻止?CSocket在发送时不会阻塞

感谢

UINT CNetServer::serveClient(LPVOID p) 
{ 
    serveClientParams* params = reinterpret_cast<serveClientParams*>(p); 
    try 
     { 
      AfxSocketInit(); 
      CSocket clientSocket; 
      clientSocket.Attach(params->ClientSocket); 
      CSocketFile file(&clientSocket); 
      CArchive arIn (&file, CArchive::load); 
      CArchive arOut(&file, CArchive::store); 
     params->ServerInstance->Consumer.Consume(arIn, arOut); 

      arOut.Flush(); 
      file.Flush(); 
        //SleepEx(1000,true); works fine is I wait till the data is sent. 
     } 
     catch(int ex) 
     { 
      CMisc::LogWriteWarning(ex, GetLastError(), "Listen Loop Communication"); 
     } 
     catch(CException* ex) 
     { 
      char buffer[1024]; 
      ex->GetErrorMessage(buffer, sizeof(buffer)); 
      CMisc::LogWriteError(buffer, SOCKET_COMUNICATION_FAILED); 
     } 
     catch(...) 
     { 
      CMisc::LogWriteWarning(0, GetLastError(), "abnormal communication termination."); 
     } 
     delete params; 
     return 0; 
} 

回答

1

我找到了解决办法,为了关闭连接而不会丢失任何没有交换的数据,你应该基本使用SO_LINGER选项,这是一个很长的故事,你可以看到在this article

但奇怪的细节部分是,MSDN在关机时看起来非常不准确,根据我的经验,LINGER选项对关机没有影响,如果您在关闭之前调用shutdown,那么随后的关闭将不会阻止!

最后,这里是新代码

UINT CNetServer::serveClient(LPVOID p) 
{ 
    serveClientParams* params = reinterpret_cast<serveClientParams*>(p); 
    try 
     { 
      AfxSocketInit(); 
      CSocket clientSocket; 
      clientSocket.Attach(params->ClientSocket); 

      struct linger linger; 
      linger.l_linger = 9; 
      linger.l_onoff = 128; 
      int fls = 0; 

      int i = clientSocket.SetSockOpt(SO_LINGER, &linger, sizeof(linger)); 
      i = clientSocket.SetSockOpt(SO_DONTLINGER, &fls, sizeof(fls)); 

      CSocketFile file(&clientSocket); 
      CArchive arIn (&file, CArchive::load); 
      CArchive arOut(&file, CArchive::store); 
      params->ServerInstance->Consumer.Consume(arIn, arOut); 

      arOut.Flush(); 
      //BOOL b = clientSocket.ShutDown(SD_BOTH); 
     } 
     catch(int ex) 
     { 
      CMisc::LogWriteWarning(ex, GetLastError(), "Listen Loop Communication"); 
     } 
     catch(CException* ex) 
     { 
      char buffer[1024]; 
      ex->GetErrorMessage(buffer, sizeof(buffer)); 
      CMisc::LogWriteError(buffer, SOCKET_COMUNICATION_FAILED); 
     } 
     catch(...) 
     { 
      CMisc::LogWriteWarning(0, GetLastError(), "abnormal communication termination."); 
     } 
     delete params; 
     return 0; 
} 
0

我没有关于该问题的确切想法在这里。无论如何请尝试以下,它可能会解决您的问题。

不允许clientSocket被销毁。为此,您可以按照以下方式动态或全局范围地创建它。

1. UINT CNetServer::serveClient(LPVOID p) 
    { 
     : 
     CSocket* clientSocket = new CSocket; 
     : 
    } 

2. CSocket clientSocket; // Global scope 

    UINT CNetServer::serveClient(LPVOID p) 
    { 
     : 
    } 
+0

这是一个非常繁忙的服务器。我不能长时间保持插座,所以你的解决方案不适用于我的情况。 – Mehran 2009-12-04 15:29:54