tags:

views:

184

answers:

2

This function is called to serve each client in a new thread. in the consume function, these archives are read and written to but the function returns before the client finishes reading all the response so the socket goes out of scope and closed, creating an exception in client. I'm assuming that any write on the CArchive should block until its read on the client side. Am I making a wrong assumption here? The code works fine if I add a delay before going out of scope ( try ) which is not a good way, I wonder is there any way to block until all the data is transferred?

Thanks

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;
}
A: 

I don't have an exact idea about the problem here. Anyway please try the following, it may solve your problem.

Do not allow clientSocket to be destroyed. For that you can either create it dynamically or in a global scope as follows.

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

2. CSocket clientSocket; // Global scope

   UINT CNetServer::serveClient(LPVOID p)
   {
       :
   }
Vadakkumpadath
It's a very busy server. I can't afford to keep the sockets for long so your solution is not applicable in my case.
Mehran
A: 

I found the solution, In order to close the connection without loosing any none exchanged data you should basically use SO_LINGER option, it's a very long story you can see the details in this article

but the strange part is, MSDN seems very inaccurate when it comes to shutdown, in my experience, LINGER options had no effect on shutdown and if you call shutdown before close then the subsequent close won't block anymore!

finally, here is the new code

   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;
}
Mehran