简体   繁体   English

升压套接字通信在一次交换后无法正常工作

[英]boost socket comms are not working past one exchange

I am converting an app which had a very simple heartbeat / status monitoring connection between two services. 我正在转换一个在两个服务之间具有非常简单的心跳/状态监视连接的应用程序。 As that now needs to be made to run on linux in addition to windows, I thought I'd use boost (v1.51, and I cannot upgrade - linux compilers are too old and windows compiler is visual studio 2005) to accomplish the task of making it platform agnostic (considering, I really would prefer not to either have two code files, one for each OS, or a littering of #defines throughout the code, when boost offers the possibility of being pleasant to read (6mos after I've checked in and forgotten this code!) 由于现在除了Windows之外,还需要在Linux上运行,因此我认为我会使用boost(v1.51,并且我无法升级-linux编译器太旧,而Windows编译器是Visual Studio 2005)才能完成任务使其与平台无关(考虑到,我真的不希望没有两个代码文件,每个操作系统一个),或者在整个代码中乱扔#defines,这时boost提供了令人愉悦的阅读可能性(我之后6mos已签入并忘记了此代码!)

My problem now, is the connection is timing out. 我现在的问题是连接超时。 Actually, it's not really working at all. 实际上,它根本不起作用。

First time through, the 'status' message is sent, it's received by the server end which sends back an appropriate response. 第一次,“状态”消息被发送,服务器端接收到该消息,并发送回适当的响应。 Server end then goes back to waiting on the socket for another message. 然后,服务器端返回到等待套接字的另一条消息。 Client end (this code), sends the 'status' message again... but this time, the server never receives it and the read_some() call blocks until the socket times out. 客户端(此代码)再次发送“状态”消息...但是这一次,服务器再也没有收到该消息,并且在套接字超时之前,read_some()调用将阻塞。 I find it really strange that 我觉得很奇怪

The server end has not changed. 服务器端未更改。 The only thing that's changed, is my having altered the client code from basic winsock2 sockets, to this code. 唯一更改的是,我已将客户端代码从基本的winsock2套接字更改为该代码。 Previously, it connected and just looped through send / recv calls until the program was aborted or the 'lockdown' message was received. 以前,它连接并只是通过发送/接收调用循环,直到程序中止或收到“锁定”消息为止。

Why would subsequent calls (to send) silently fail to send anything on the socket and, what do I need to adjust in order to restore the simple send / recv flow? 为什么后续的调用(发送)在无提示的情况下无法在套接字上发送任何内容,并且,为了恢复简单的send / recv流,我需要进行哪些调整?

#include <boost/signals2/signal.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

using boost::asio::ip::tcp;
using namespace std;

boost::system::error_code ServiceMonitorThread::ConnectToPeer(
    tcp::socket &socket,
    tcp::resolver::iterator endpoint_iterator)
{
    boost::system::error_code error;
    int tries = 0;

    for (; tries < maxTriesBeforeAbort; tries++)
    {
        boost::asio::connect(socket, endpoint_iterator, error);

        if (!error)
        {
            break;
        }
        else if (error != make_error_code(boost::system::errc::success))
        {
            // Error connecting to service... may not be running?
            cerr << error.message() << endl;
            boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
        }
    }

    if (tries == maxTriesBeforeAbort)
    {
        error = make_error_code(boost::system::errc::host_unreachable);
    }

    return error;
}

// Main thread-loop routine.
void ServiceMonitorThread::run() 
{
    boost::system::error_code error;

    tcp::resolver resolver(io_service);
    tcp::resolver::query query(hostnameOrAddress, to_string(port));
    tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

    tcp::socket socket(io_service);

    error = ConnectToPeer(socket, endpoint_iterator);
    if (error && error == boost::system::errc::host_unreachable)
    {
        TerminateProgram();
    }

    boost::asio::streambuf command;
    std::ostream command_stream(&command);
    command_stream << "status\n";

    boost::array<char, 10> response;
    int retry = 0;

    while (retry < maxTriesBeforeAbort)
    {
        // A 1s request interval is more than sufficient for status checking.
        boost::this_thread::sleep_for(boost::chrono::seconds(1));

        // Send the command to the network monitor server service.
        boost::asio::write(socket, command, error);

        if (error)
        {
            // Error sending to socket
            cerr << error.message() << endl;
            retry++;
            continue;
        }

        // Clear the response buffer, then read the network monitor status.
        response.assign(0);
        /* size_t bytes_read = */ socket.read_some(boost::asio::buffer(response), error);

        if (error)
        {
            if (error == make_error_code(boost::asio::error::eof))
            {
                // Connection was dropped, re-connect to the service.
                error = ConnectToPeer(socket, endpoint_iterator);
                if (error && error == make_error_code(boost::system::errc::host_unreachable))
                {
                    TerminateProgram();
                }
                continue;
            }
            else 
            {
                cerr << error.message() << endl;
                retry++;
                continue;
            }
        }

        // Examine the response message.
        if (strncmp(response.data(), "normal", 6) != 0)
        {
            retry++;

            // If we received the lockdown response, then terminate.
            if (strncmp(response.data(), "lockdown", 8) == 0)
            {
                break;
            }

            // Not an expected response, potential error, retry to see if it was merely an aberration.
            continue;
        }

        // If we arrived here, the exchange was successful; reset the retry count.
        if (retry > 0)
        {
            retry = 0;
        }
    }

    // If retry count was incremented, then we have likely encountered an issue; shut things down.
    if (retry != 0)
    {
        TerminateProgram();
    }
}

When a streambuf is provided directly to an I/O operation as the buffer, then the I/O operation will manage the input sequence appropriately by either commiting read data or consuming written data. 当将流streambuf直接提供给I / O操作作为缓冲区时,I / O操作将通过提交读取数据或使用写入数据来适当地管理输入序列。 Hence, in the following code, command is empty after the first iteration: 因此,在以下代码中, command在第一次迭代后为空:

boost::asio::streambuf command;
std::ostream command_stream(&command);
command_stream << "status\n";
// `command`'s input sequence contains "status\n".

while (retry < maxTriesBeforeAbort)
{
  ...

  // write all of `command`'s input sequence to the socket.
  boost::asio::write(socket, command, error);
  // `command.size()` is 0, as the write operation will consume the data.
  // Subsequent write operations with `command` will be no-ops.

  ...
}

One solution would be to use std::string as the buffer: 一种解决方案是使用std::string作为缓冲区:

std::string command("status\n");

while (retry < maxTriesBeforeAbort)
{
  ...

  boost::asio::write(socket, boost::asio::buffer(command), error);

  ...
}

For more details on streambuf usage, consider reading this answer. 有关streambuf使用的更多详细信息,请考虑阅读答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM