C ++ WinSock2 ждет, пока клиент отправит данные - PullRequest
0 голосов
/ 01 июля 2019

У меня есть многопоточный сервер сокетов, который должен непрерывно общаться с клиентом, поэтому я положил recv в while(true), чтобы поддерживать соединение, пока одна из сторон не закроет его.У меня проблема в том, что когда клиент ничего не отправляет, сервер продолжает пытаться получить данные, которые в конечном итоге приводят к сбою, потому что он читает из ничего, поэтому я хочу знать, есть ли способ заставить recv остановиться до тех пор, покафактические данные для получения.

Вот код функции, которая обрабатывает соединение с клиентом:

void Communicator::clientHandler(SOCKET client)
{
    try
    {
        while (true)
        {
            char codeBuff[1];
            recv(client, codeBuff, 1, 0);
            int code = static_cast<int>(static_cast<unsigned char>(codeBuff[0]));
            char lengthBuff[4];
            recv(client, lengthBuff, 4, 0);
            int dataLength = lengthBuff[0] << 24 | lengthBuff[1] << 16 | lengthBuff[2] << 8 | lengthBuff[3];
            char* dataBuff = new char(dataLength);
            recv(client, dataBuff, dataLength, 0);
            dataBuff[dataLength - 1] = 0;

            std::vector<char> dataVec(dataBuff, dataBuff + dataLength);
            Request r = {
                code,
                std::time(nullptr),
                dataVec
            };

            std::copy(dataVec.begin(), dataVec.end(), std::ostream_iterator<char>(std::cout, "")); // For debug purposes, prints infintiely

            IRequestHandler* handler = nullptr;
            {
                std::lock_guard<std::mutex> locker(m_clientsMu);
                handler = m_clients.find(client)->second;
            }

            if (handler->isRequestRelevant(r))
            {
                RequestResult res = handler->handleRequest(r);
                {
                    std::lock_guard<std::mutex> locker(m_clientsMu);
                    delete[] m_clients.find(client)->second;
                    m_clients.find(client)->second = res.newHandler;
                }
                send(client, &res.response[0], res.response.size(), 0);
            }
            else
            {
                ErrorResponse res = { "Invalid request type" };
                std::vector<char> packet = JsonPacketSerializer::serializeResponse(res);
                send(client, &packet[0], packet.size(), 0);
            }
        }
    }
    catch (...)
    {
        closesocket(client);
        throw;
    }
}

Некоторые базовые коды Python, которые я использую для тестирования сервера:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
s.connect(('127.0.0.1', 8080))
s.send(bytes([101, 0, 0, 0, 40, 123, 34, 112, 97, 115, 115, 119, 111, 114, 100, 34, 58, 34, 49, 50, 51, 52, 53, 54, 34,
              44, 34, 117, 115, 101, 114, 110, 97, 109, 101, 34, 58, 34, 116, 101, 115, 116, 34, 125]))
msg = s.recv(1024)
print(msg)

1 Ответ

1 голос
/ 01 июля 2019
char* dataBuff = new char(dataLength);

Это создает один char, наиболее вероятно со значением dataLength & 255 и dataBuff будет указывать на это один char.Вы выделяете массив char следующим образом:

char* dataBuff = new char[dataLength];

Вы также должны освободить память позже:

delete[] dataBuff;

Вам также необходимо позаботиться о возвращаемом значении из recv это число полученных байтов (или SOCKET_ERROR для обозначения ошибки).

...