Sockets 如何在基于boost::asio的异步模式下接收未知大小的缓冲区
我正在尝试接收大小未知的缓冲区,部分代码如下:Sockets 如何在基于boost::asio的异步模式下接收未知大小的缓冲区,sockets,boost-asio,asyncsocket,Sockets,Boost Asio,Asyncsocket,我正在尝试接收大小未知的缓冲区,部分代码如下: void Connection::asyncRead() { auto self(shared_from_this()); socket_.async_read_some(boost::asio::buffer(buffer_out), [this, self](boost::system::error_code ec, std::size_t length) { OnRead(ec, le
void Connection::asyncRead()
{
auto self(shared_from_this());
socket_.async_read_some(boost::asio::buffer(buffer_out),
[this, self](boost::system::error_code ec, std::size_t length)
{
OnRead(ec, length);
});
}
我不知道缓冲区的大小,所以我尝试在固定大小的缓冲区中接收缓冲区,如何知道缓冲区是否结束?如果要发送/接收没有固定大小的消息,可以使用 定义邮件标题的方法,例如使用4字节字段来存储邮件内容的大小:
[header(4 bytes) to store the size of message][content of message]
然后你总是知道第一步是读取4个字节,
为数据准备缓冲区并读取更多数据,直到缓冲区填满
另一种方法是关闭套接字(下面是伪代码)
通过调用发送端[1]中的sock.shutdown()
,您可以通知
整个消息被发送的接收方。
然后在消息读取后的接收端[2],您应该检查ec
错误代码变量的状态是否为boost::asio::eof
。
如果您得到文件的结尾
,您就知道消息已完成。如果ec
与eof
不同,则表示发生了错误
从1.66 boost版本开始,您可以使用动态缓冲区
来存储数据,它将字符串或向量调整为缓冲区。
或者可以考虑<代码> StRubf读取非固定缓冲区。
编辑 添加了
动态缓冲区的使用。
根据参考资料,dynamic\u buffer
可以用在自由函数中,如async\u read
,async\u直到,但不能用在async\u read\u some
中作为套接字的成员函数。以下是客户端和服务器的代码:
服务器:
using namespace boost;
struct Data {
std::shared_ptr<asio::ip::tcp::socket> sock;
std::string buf; // buf is empty [1]
};
void readHandler (
const boost::system::error_code& ec,
size_t length,
std::shared_ptr<Data> d) {
std::cout << "readHandler" << std::endl;
if (ec == boost::asio::error::eof)
{
// here we got the whole message
std::cout << d->buf << std::endl;
}
else
{
std::cout << "Error" << std::endl;
}
}
int main() {
try {
asio::ip::tcp::endpoint ep(asio::ip::address_v4::any(),9999);
asio::io_service ios;
asio::ip::tcp::acceptor acceptor(ios, ep);
std::shared_ptr<asio::ip::tcp::socket> sock{new asio::ip::tcp::socket(ios)};
acceptor.accept(*sock);
std::shared_ptr<Data> data(new Data);
data->sock = move(sock);
boost::asio::async_read (*(data->sock), asio::dynamic_buffer(data->buf),
std::bind(readHandler,std::placeholders::_1, std::placeholders::_2,data)); // [2]
ios.run(); // wait until async_write is complete
}
catch (system::system_error &e) {
std::cout << "error " << e.what() << std::endl;
}
return 0;
}
正如您所看到的,我们正在以1秒的延迟从字符串中逐个发送字符。所以,当您先启动服务器,然后启动客户机时,服务器应该在大约12秒后收到整个消息async_read
正在服务器中等待,直到eof
到来-客户端通过调用socket上的shutdown
发送 如果要发送/接收大小不固定的邮件,可以使用
定义邮件标题的方法,例如使用4字节字段来存储邮件内容的大小:
[header(4 bytes) to store the size of message][content of message]
然后你总是知道第一步是读取4个字节,
为数据准备缓冲区并读取更多数据,直到缓冲区填满
另一种方法是关闭套接字(下面是伪代码)
通过调用发送端[1]中的sock.shutdown()
,您可以通知
整个消息被发送的接收方。
然后在消息读取后的接收端[2],您应该检查ec
错误代码变量的状态是否为boost::asio::eof
。
如果您得到文件的结尾
,您就知道消息已完成。如果ec
与eof
不同,则表示发生了错误
从1.66 boost版本开始,您可以使用动态缓冲区
来存储数据,它将字符串或向量调整为缓冲区。
或者可以考虑<代码> StRubf读取非固定缓冲区。
编辑
添加了动态缓冲区的使用。
根据参考资料,dynamic\u buffer
可以用在自由函数中,如async\u read
,async\u直到,但不能用在async\u read\u some
中作为套接字的成员函数。以下是客户端和服务器的代码:
服务器:
using namespace boost;
struct Data {
std::shared_ptr<asio::ip::tcp::socket> sock;
std::string buf; // buf is empty [1]
};
void readHandler (
const boost::system::error_code& ec,
size_t length,
std::shared_ptr<Data> d) {
std::cout << "readHandler" << std::endl;
if (ec == boost::asio::error::eof)
{
// here we got the whole message
std::cout << d->buf << std::endl;
}
else
{
std::cout << "Error" << std::endl;
}
}
int main() {
try {
asio::ip::tcp::endpoint ep(asio::ip::address_v4::any(),9999);
asio::io_service ios;
asio::ip::tcp::acceptor acceptor(ios, ep);
std::shared_ptr<asio::ip::tcp::socket> sock{new asio::ip::tcp::socket(ios)};
acceptor.accept(*sock);
std::shared_ptr<Data> data(new Data);
data->sock = move(sock);
boost::asio::async_read (*(data->sock), asio::dynamic_buffer(data->buf),
std::bind(readHandler,std::placeholders::_1, std::placeholders::_2,data)); // [2]
ios.run(); // wait until async_write is complete
}
catch (system::system_error &e) {
std::cout << "error " << e.what() << std::endl;
}
return 0;
}
正如您所看到的,我们正在以1秒的延迟从字符串中逐个发送字符。所以,当您先启动服务器,然后启动客户机时,服务器应该在大约12秒后收到整个消息async_read
正在服务器中等待,直到eof
到来-客户端通过调用socket上的shutdown
发送 谢谢,你能给我举一个通过dynamic\u buffer
接收缓冲区的例子吗?互联网上的信息很少,再次谢谢。我在使用asio::dynamic\u buffer(buf)
时无法异步读取,onRead处理程序将不会被调用。但是,当我使用boost::asio::buffer(buffer\u out)
时成功了(buffer_out是公共向量缓冲区),我将确保缓冲区的生存期,您是否遇到过此问题或可能有什么问题?如果不查看整个代码,很难确定问题出在哪里。当您使用异步操作时,您需要确保缓冲区存在,直到异步操作结束。谢谢,您能给我展示一个通过dynamic接收缓冲区的示例吗c_buffer
,互联网上的信息很少,再次感谢。当我使用asio::dynamic_buffer(buf)
时,我无法异步读取,并且不会调用onRead处理程序。但是当我使用boost::asio::buffer(buffer\u out)
(buffer\u out是公共向量缓冲区)时,我成功了,我将确保缓冲区的生存期,您是否遇到过此问题或可能出现了什么问题?如果不查看整个代码,很难确定问题在哪里。当您使用异步操作时,您需要确保缓冲区存在,直到异步操作结束。