boost-asio - 关于在 async_read_until 之后使用 async_write 的问题

标签 boost-asio asyncsocket

我的代码如下:

boost::asio::streambuf b1;

boost::asio::async_read_until(upstream_socket_, b1, '@',
           boost::bind(&bridge::handle_upstream_read, shared_from_this(),
           boost::asio::placeholders::error,
           boost::asio::placeholders::bytes_transferred));


void handle_upstream1_read(const boost::system::error_code& error,
                            const size_t& bytes_transferred)
  {
     if (!error)
     {

       async_write(downstream_socket_,
          b2,
          boost::bind(&bridge::handle_downstream_write,
          shared_from_this(),
          boost::asio::placeholders::error));  
     }
     else
        close();
  }

根据async_read_until的文档,http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/async_read_until/overload1.html , 成功执行 async_read_until 操作后,streambuf 可能包含超出分隔符的其他数据。应用程序通常会将该数据保留在 Streambuf 中,以便后续的 async_read_until 操作进行检查。

我知道streambuf可能包含超出分隔符的附加数据,但是,就我而言,它会将这些附加数据(字符'@'之外的数据)写入async_write操作内的downstream_socket_吗?或者async_write函数是否足够聪明,不会在下次调用handle_upstream1_read函数之前写入这些附加数据?

根据文档中的方法,streambuf中的数据首先存储在istream中( std::istream response_stream(&streambuf); ) 然后使用 std::getline() 函数将其放入字符串中。

我真的需要先将streambuf存储在istream中,然后将其转换为字符串,然后将其转换回char数组(以便我可以将char数组发送到downstream_socket_),而不是仅仅使用async_write来写入数据(最多但不包括分隔符“@”)到下游套接字?

我更喜欢第二种方法,这样我就不需要对数据进行多次转换。然而,当我尝试第二种方法时,似乎出了问题。

我的理想情况是:

  1. upstream_socket_ 使用 async_read_until 接收到 xxxx@yyyy
  2. xxxx@ 写入下游_socket_
  3. upstream_socket_ 使用 async_read_until 收到 zzzz@kkkk
  4. yyyyzzzz@ 写入下游_socket_

看来async_write操作仍然将超出分隔符的数据写入downstream_socket_。 (但我对此不是100%确定)

如果有人能提供一点帮助,我将不胜感激!

最佳答案

async_write()当所有 streambuf 时,正在使用的重载被视为完成。的数据,即其输入序列,已写入 WriteStream(套接字)。相当于调用:

boost::asio::async_write(stream, streambuf,
    boost::asio::transfer_all(), handler);

可以通过调用 async_write() 来限制从 Streambuf 对象写入和消耗的字节数。 boost::asio::transfer_exactly 过载完成条件:

boost::asio::async_write(stream, streambuf, 
    boost::asio::transfer_exactly(n), handler);

或者,可以直接从streambuf的输入序列写入。但是,需要显式地从 Streambuf 中消费。

boost::asio::async_write(stream,
    boost::asio::buffer(streambuf.data(), n), handler);
// Within the completion handler...
streambuf.consume(n);

请注意,当 async_read_until()操作完成后,完成处理程序的 bytes_transferred 参数包含 Streambuf 输入序列中直到并包括分隔符的字节数,如果发生错误,则为 0


这是一个完整的示例 demonstrating使用这两种方法。该示例是使用同步操作编写的,以尝试简化流程:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

// This example is not interested in the handlers, so provide a noop function
// that will be passed to bind to meet the handler concept requirements.
void noop() {}

/// @brief Helper function that extracts a string from a streambuf.
std::string make_string(
  boost::asio::streambuf& streambuf,
  std::size_t n)
{
  return std::string(
      boost::asio::buffers_begin(streambuf.data()),
      boost::asio::buffers_begin(streambuf.data()) + n);
}

int main()
{
  using boost::asio::ip::tcp;
  boost::asio::io_service io_service;

  // Create all I/O objects.
  tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 0));
  tcp::socket server_socket(io_service);
  tcp::socket client_socket(io_service);

  // Connect client and server sockets.
  acceptor.async_accept(server_socket, boost::bind(&noop));
  client_socket.async_connect(acceptor.local_endpoint(), boost::bind(&noop));
  io_service.run();

  // Mockup write_buffer as if it read "xxxx@yyyy" with read_until()
  // using '@' as a delimiter.
  boost::asio::streambuf write_buffer;
  std::ostream output(&write_buffer);
  output << "xxxx@yyyy";
  assert(write_buffer.size() == 9);
  auto bytes_transferred = 5;

  // Write to server.
  boost::asio::write(server_socket, write_buffer,
      boost::asio::transfer_exactly(bytes_transferred));
   // Verify write operation consumed part of the input sequence.
  assert(write_buffer.size() == 4);

  // Read from client.
  boost::asio::streambuf read_buffer;
  bytes_transferred = boost::asio::read(
      client_socket, read_buffer.prepare(bytes_transferred));
  read_buffer.commit(bytes_transferred);

  // Copy from the read buffers input sequence.
  std::cout << "Read: " << 
               make_string(read_buffer, bytes_transferred) << std::endl;
  read_buffer.consume(bytes_transferred);

  // Mockup write_buffer as if it read "zzzz@kkkk" with read_until()
  // using '@' as a delimiter.
  output << "zzzz@kkkk";
  assert(write_buffer.size() == 13); 
  bytes_transferred = 9; // yyyyzzzz@

  // Write to server.
  boost::asio::write(server_socket, buffer(write_buffer.data(),
      bytes_transferred));
  // Verify write operation did not consume the input sequence.
  assert(write_buffer.size() == 13);
  write_buffer.consume(bytes_transferred);

  // Read from client.
  bytes_transferred = boost::asio::read(
      client_socket, read_buffer.prepare(bytes_transferred));
  read_buffer.commit(bytes_transferred);

  // Copy from the read buffers input sequence.
  std::cout << "Read: " << 
               make_string(read_buffer, bytes_transferred) << std::endl;
  read_buffer.consume(bytes_transferred);
}

输出:

Read: xxxx@
Read: yyyyzzzz@

其他一些注意事项:

  • streambuf 拥有内存,std::istreamstd::ostream 使用内存。当需要提取格式化输入或插入格式化输出时,使用流可能是一个好主意。例如,当您希望将字符串“123”读取为整数123时。
  • 可以直接访问streambuf的输入序列并对其进行迭代。在上面的示例中,我使用 boost::asio::buffers_begin()通过迭代streambuf的输入序列来帮助构建std::string

    std::string(
        boost::asio::buffers_begin(streambuf.data()),
        boost::asio::buffers_begin(streambuf.data()) + n);
    
  • 正在使用基于流的传输协议(protocol),因此将传入数据作为流处理。请注意,即使中间服务器重新构造消息并在一次写入操作中发送 "xxxx@" 并在后续写入操作中发送 "yyyyzzzz@",下游也可能会读取 “xxxx@yyyy” 在单个读取操作中。

关于boost-asio - 关于在 async_read_until 之后使用 async_write 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28511977/

相关文章:

c# - 在 Windows Server 2008 R2 上使用异步套接字导致 100% CPU 使用率

c++ - 用 boost::asio::io_service 替换 select()

c++ - 使用 boost::asio(pion 库)的 https 服务器提示 "no shared cipher"

c++ - 永远运行 boost asio io_service

c++ - 发送/获取结构时使用 streambuf

c++ - ZMQ 经销商 - 路由器通讯

iOS 如何使用 ASyncSocket 进行 SSL 握手?

iphone - 为什么 Objective-C 将 JSON 值转换为 ASCII 字符代码的散列?

c# - C#SocketAsyncEventArgs停止触发完成的事件

c++ - 为什么 boost::asio::read 缓冲区数据大小小于读取大小?