开发者

CSocket is not blocking on send

开发者 https://www.devze.com 2022-12-13 06:31 出处:网络
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 respon

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::LogWri开发者_如何学编程teError(buffer, SOCKET_COMUNICATION_FAILED); 
        }
        catch(...)
        {
            CMisc::LogWriteWarning(0, GetLastError(), "abnormal communication termination.");
        }
        delete params;
        return 0;
}


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


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)
   {
       :
   }
0

精彩评论

暂无评论...
验证码 换一张
取 消