CSocket не блокируется при отправке - PullRequest
1 голос
/ 03 декабря 2009

Эта функция вызывается для обслуживания каждого клиента в новом потоке. в функции потребления эти архивы читаются и записываются, но функция возвращается до того, как клиент завершит чтение всего ответа, поэтому сокет выходит из области действия и закрывается, создавая исключение в клиенте. Я предполагаю, что любая запись в 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 ]

1 голос
/ 03 декабря 2009

Я нашел решение: чтобы закрыть соединение без потери данных, которыми не обменивались, вы должны в основном использовать опцию SO_LINGER, это очень длинная история, которую вы можете увидеть в этой статье

но странно то, что 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 голосов
/ 03 декабря 2009

У меня нет точного представления о проблеме здесь. В любом случае, попробуйте следующее, это может решить вашу проблему.

Не позволяйте уничтожить clientSocket. Для этого вы можете создать его динамически или в глобальной области видимости следующим образом.

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

2. CSocket clientSocket; // Global scope

   UINT CNetServer::serveClient(LPVOID p)
   {
       :
   }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...