我有这个要求,我的应用程序必须通过套接字连接到另一个应用程序,并且必须长时间保持持久连接。我的应用程序将是一个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读取持久套接字中的所有数据?不使用升压。
答案 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
)。