повышение:: asio, чисто разъединяющийся

Иногда повышение:: asio, кажется, разъединяется, прежде чем я захочу его к, т.е. прежде чем сервер правильно обработает разъединение. Я не уверен, как это возможно, потому что клиент, кажется, думает его полностью отправленный сообщение, все же когда сервер не испускает ошибку его даже чтение заголовок сообщения... Во время тестирования это только происходит, возможно, каждый 5-й раз, сервер получает клиентское сообщение закрытия и разъединяет клиент чисто.

Ошибка: "Существующее соединение было насильственно закрыто удаленным хостом"

Клиент, разъединяющийся:

void disconnect()
{
    boost::system::error_code error;
    //just creates a simple buffer with a shutdown header
    boost::uint8_t *packet = createPacket(PC_SHUTDOWN,0);
    //sends it
    if(!sendBlocking(socket,packet,&error))
    {
        //didnt get here in my tests, so its not that the write failed...
        logWrite(LOG_ERROR,"server",
            std::string("Error sending shutdown message.\n")
            + boost::system::system_error(error).what());
    }

    //actaully disconnect
    socket.close();
    ioService.stop();
}
bool sendBlocking(boost::asio::ip::tcp::socket &socket,
    boost::uint8_t *data, boost::system::error_code* error)
{
    //get the length section from the message
    boost::uint16_t len = *(boost::uint16_t*)(data - 3);
    //send it
    asio::write(socket, asio::buffer(data-3,len+3),
        asio::transfer_all(), *error);
    deletePacket(data);
    return !(*error);
}

Сервер:

void Client::clientShutdown()
{
    //not getting here in problem cases
    disconnect();
}
void Client::packetHandler(boost::uint8_t type, boost::uint8_t *data,
    boost::uint16_t len, const boost::system::error_code& error)
{
    if(error)
    {
        //error handled here
        delete[] data;
        std::stringstream ss;
        ss << "Error recieving packet.\n";
        ss << logInfo() << "\n";
        ss << "Error: " << boost::system::system_error(error).what();
        logWrite(LOG_ERROR,"Client",ss.str());

        disconnect();
    }
    else
    {
        //call handlers based on type, most will then call startRead when
        //done to get the next packet. Note however, that clientShutdown
        //does not
        ...
    }
}



void startRead(boost::asio::ip::tcp::socket &socket, PacketHandler handler)
{
    boost::uint8_t *header = new boost::uint8_t[3];
    boost::asio::async_read(socket,boost::asio::buffer(header,3),
        boost::bind(&handleReadHeader,&socket,handler,header, 
        boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error));
}
void handleReadHeader(boost::asio::ip::tcp::socket *socket, PacketHandler handler,
    boost::uint8_t *header, size_t len, const boost::system::error_code& error)
{
    if(error)
    {
        //error "thrown" here, len always = 0 in problem cases...
        delete[] header;
        handler(0,0,0,error);
    }
    else
    {
        assert(len == 3);
        boost::uint16_t payLoadLen  = *((boost::uint16_t*)(header + 0));
        boost::uint8_t  type        = *((boost::uint8_t*) (header + 2));
        delete[] header;
        boost::uint8_t *payLoad = new boost::uint8_t[payLoadLen];

        boost::asio::async_read(*socket,boost::asio::buffer(payLoad,payLoadLen),
            boost::bind(&handleReadBody,socket,handler,
            type,payLoad,payLoadLen,
            boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error));
    }
}
void handleReadBody(ip::tcp::socket *socket, PacketHandler handler,
    boost::uint8_t type, boost::uint8_t *payLoad, boost::uint16_t len,
    size_t readLen, const boost::system::error_code& error)
{
    if(error)
    {
        delete[] payLoad;
        handler(0,0,0,error);
    }
    else
    {
        assert(len == readLen);
        handler(type,payLoad,len,error);
        //delete[] payLoad;
    }
}
26
задан GrahamS 18 June 2010 в 08:25
поделиться

4 ответа

Я думаю, вам, вероятно, следует позвонить в сокет . shutdown (boost :: asio :: ip :: tcp :: socket :: shutdown_both, ec) перед вызовом socket.close () .

В документации boost :: asio для basic_stream_socket :: close указано:

Для переносимого поведения в отношении постепенного закрытия подключенного сокета вызовите shutdown () перед закрытием сокета.

Это должно гарантировать, что все ожидающие операции на сокете должным образом отменены и все буферы очищаются до вызова socket.close.

27
ответ дан 28 November 2019 в 07:04
поделиться

Может быть, вот что происходит:

  • Клиент посылает пакет отключения
  • Клиент отключает сокет
  • Вызывается обработчик чтения сервера, но есть ошибка, связанная с пакетом отключения, потому что сокет уже закрыт.

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

5
ответ дан 28 November 2019 в 07:04
поделиться

Используйте async_write() и поместите socket.close() внутрь обработчика записи. Это гарантирует, что пакет обрабатывается boost asio и не игнорируется в середине обработки (из-за вызовов close()).

4
ответ дан 28 November 2019 в 07:04
поделиться

У меня очень похожая проблема. Я считаю, что это связано с повторным использованием соединений Windows.Следующее знакомо?

  • вы получаете эту ошибку сразу после запуска программы, а не после установления соединения?
  • Ошибка никогда не возникает, если вы ждете более 4 минут перед перезапуском приложения?

Спецификации tcp указывают, что по умолчанию он должен ждать четыре минуты для окончательного подтверждения при закрытии tcp-соединения. Вы можете увидеть эти соединения в состоянии FIN_WAIT, используя netstat. ОС Windows обнаруживает, когда вы пытаетесь подключиться к той же самой системе, берет эти частично закрытые соединения и перерабатывает их. Ваш второй вызов программы получает «закрытое» соединение, оставленное первым запуском. Он получает следующее подтверждение, а затем действительно закрывается.

4
ответ дан 28 November 2019 в 07:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: