Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 如何在基于boost::asio的异步模式下接收未知大小的缓冲区_Sockets_Boost Asio_Asyncsocket - Fatal编程技术网

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是公共向量缓冲区)时,我成功了,我将确保缓冲区的生存期,您是否遇到过此问题或可能出现了什么问题?如果不查看整个代码,很难确定问题在哪里。当您使用异步操作时,您需要确保缓冲区存在,直到异步操作结束。