Asio与持久套接字的双向通讯

时间:2019-04-11 14:13:46

标签: c++ boost-asio

我有这个要求,我的应用程序必须通过套接字连接到另一个应用程序,并且必须长时间保持持久连接。我的应用程序将是一个TCP客户端,另一个是TCP服务器。我的应用程序将发送命令,服务器将做出相应响应。

当前面临的问题是如何从服务器读取字符串中的全部数据并返回给app,这将发出下一个命令。同步读取(使用asio::read)似乎是一个不错的选择,直到观察到套接字挂起直到终止服务器为止。查看文档,我发现该库可以正常工作。

  

他的函数用于从流中读取一定数量的字节数据。该调用将一直阻塞,直到满足以下条件之一:    1.提供的缓冲区已满。即,传输的字节等于缓冲区大小的总和。   2.发生错误。

问题是由于服务器响应的变化,我不知道正确的缓冲区大小。因此,如果我放置的缓冲区太小,它会返回正常值,但会丢失一些数据。如果我放的太大,它将永久挂起,直到服务器退出。

所以我想我会做异步阅读。它只能工作一次,在读取全部数据之前,我不知道如何获取数据。

这是相关的异步代码

#define ASIO_STANDALONE 1

#include <iostream>
#include <asio.hpp>

int main()
{
    asio::io_context context;
    size_t reply_length;
    size_t length = 1024;
    std::vector<char> buffer;

    //create socket
    asio::ip::tcp::socket socket(context);
    socket.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 8088));

    std::string dataOut = "list --files"; //some command to write
    std::error_code error;

    asio::write(socket, asio::buffer(dataOut), error);
    if (!error)
    {
        std::cout << "Receiving...!" << std::endl;
        buffer.resize(length);
        asio::async_read(socket, asio::buffer(buffer), [&buffer, &context](const asio::error_code &ec, std::size_t bytes_transferred) {
            std::copy(buffer.begin(), buffer.end(), std::ostream_iterator<char>(std::cout, ""));
            std::cout << "\nRead total of:" << bytes_transferred << "\n";
            context.run();
        });
    }
    else
    {
        std::cout << "send failed: " << error.message() << std::endl;
    }

    context.run();
}

搜索并不能解决我的问题。

所以我的问题是,如何使用asio读取持久套接字中的所有数据?不使用升压。

1 个答案:

答案 0 :(得分:1)

您需要循环async_read个呼叫。如果您不希望客户端挂起读取操作,则可以定义最小的缓冲区,即1字节。

Define函数,该函数根据async_read的处理程序签名使用 socket buffer 和两个其他参数,并且该函数使用async_read进行自身调用以构成循环async_read调用-读取直到发生某些错误:

void onRead (
    asio::ip::tcp::socket&    socket,
    std::array<char,1>&       buf,
    const system::error_code& ec, 
    std::size_t               bytes)
{
    if (ec)
    {
        if (ec == asio::error::eof && bytes == 1)
            std::cout << buf[0];
        return;
    }

    std::cout << buf[0];   
    asio::async_read(socket,asio::buffer(buf), 
        std::bind(onRead, std::ref(socket), std::ref(buf),
          std::placeholders::_1, // error code
          std::placeholders::_2)); // transferred bytes
}

以及main中的更改:

std::array<char,1> buf;
asio::write(socket, asio::buffer(dataOut), error);

if (!error)
{
    std::cout << "Receiving...!" << std::endl;               

    asio::async_read(socket, asio::buffer(buf), 
        std::bind(onRead, std::ref(socket), std::ref(buf),
         std::placeholders::_1,
         std::placeholders::_2));

    context.run();
}
else
{
    std::cout << "send failed: " << error.message() << std::endl;
}

(我正在使用Boost,因此您应该在system::error_code上替换asio::error_code)。