【问题标题】:Asio two way communication with peristence socketAsio 与持久套接字的双向通信
【发布时间】:2019-04-11 14:13:45
【问题描述】:

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

现在面临的问题是如何从服务器读取整个数据字符串并返回应用程序,该应用程序将发出下一个命令。同步读取(使用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 读取持久套接字中的所有数据?我没有使用 boost。

【问题讨论】:

    标签: c++ boost-asio


    【解决方案1】:

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

    根据async_read的handler签名,定义一个带有socketbuffer和两个附加参数的函数,这个函数用async_read调用自己,形成@987654324的循环@ 调用 - 它会一直读取直到发生错误:

    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,所以你应该在 asio::error_code 上替换 system::error_code)。

    【讨论】:

    • 很好的解释和代码。让我玩一玩,以确保我了解一切。我会回来的!
    • @StefanoMtangoo 没问题,很高兴为您提供帮助 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 2012-01-26
    • 2013-04-10
    • 1970-01-01
    相关资源
    最近更新 更多