CSocket在发送时没有阻塞

时间:2009-12-02 23:41:36

标签: c++ mfc sockets

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

由于

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

2 个答案:

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

答案 1 :(得分:0)

我对这个问题没有确切的想法。无论如何请尝试以下,它可以解决您的问题。

不允许销毁clientSocket。为此,您可以动态创建它,也可以在全局范围内创建它,如下所示。

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

2. CSocket clientSocket; // Global scope

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