boost :: asio readsome函数似乎不起作用

时间:2016-06-26 11:21:00

标签: c++ boost boost-asio

我目前遇到使用boost :: asio的麻烦,我想在下面的代码中编写和读取。写入工作正常,但读取总是返回零。实际上我也发现每个网站都指的是

  

read_some

功能而不是

  

readsome

我在库中的系统上的功能......

有人能给我一个暗示吗?

boost::asio::ip::tcp::iostream tcp_stream;
tcp_stream.connect("localhost", "12345");

while(1)
{
    char inp[6]={0,0,0,0,0,0};

    tcp_stream<<"Test"<<std::endl;//Works fine get it with netcat (nc -l 12345)

    size_t r = tcp_stream.readsome(inp,5);//Always 0

    //std::string a;
    //tcp_stream>>a; //Works but blocks and gives me all bytes it has.
    //std::cout<<a<<std::endl;

    //std::cout<<"RDBUF: "<<tcp_stream.rdbuf();
    //rdbuf blocks here, never resuming and outputting 
    //everything I write with netcat to command line...
    if(r>0)
    {
        std::cout<<inp<<std::endl;
    }

    else //<<< always goes here
    {
        std::cout<<"received nothing!"<<std::endl;


    }
    sleep(1);
}

我想要的是我从当前界面读取0-5个字节。 (非阻塞)

1 个答案:

答案 0 :(得分:1)

问题在于std::basic_istream<>::read_some()会从关联的streambuf输入序列中读取,而asio::basic_socket_streambuf的输入序列包含已读取的数据从套接字,但尚未从streambuf消耗。它不包括可以在不阻塞的情况下从套接字读取的数据。 [1]

要解决此问题,可以确定可以在不阻塞streambuf及其底层套接字的情况下读取的数据量,然后发出std::basic_istream<>read()操作:

/// @brief Read up to `n` characters from `stream` and store them
///        into `buffer` without blocking.  This may not read all
///        of the requested amount of bytes.
template <typename... Args>
std::streamsize readsome(
  boost::asio::basic_socket_iostream<Args...>& stream,
  char* buffer,
  std::streamsize n)
{
  std::streamsize available =
    stream.rdbuf()->in_avail()     // available on input sequence
    + stream.rdbuf()->available(); // available on socket
  n = std::min(n, available);
  if (n == 0) return 0;

  stream.read(buffer, n);
  return n;
}

以下是此功能的完整示例demonstrating

#include <chrono>     // std::chrono::seconds
#include <iostream>   // std::cout, std::endl
#include <string>     // std::to_string
#include <thread>     // std::thread
#include <boost/asio.hpp>

/// @brief Read up to `n` characters from `stream` and store them
///        into `buffer` without blocking.  This may not read all
///        of the requested amount of bytes.
template <typename... Args>
std::streamsize readsome(
  boost::asio::basic_socket_iostream<Args...>& stream,
  char* buffer,
  std::streamsize n)
{
  std::streamsize available =
    stream.rdbuf()->in_avail()     // available on input sequence
    + stream.rdbuf()->available(); // available on socket
  n = std::min(n, available);
  if (n == 0) return 0;

  stream.read(buffer, n);
  return n;
}

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

  const std::array<char, 6> expected_data = {100, 101, 102, 103, 104, 105};

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

  // Run stream in its own thread.
  std::thread client_thread(
    [&]
    {
      // Connect the stream to the acceptor.
      auto endpoint = acceptor.local_endpoint();
      tcp::iostream stream(endpoint.address().to_string(),
                           std::to_string(endpoint.port()));

      // Block until 6 bytes are available.
      while (stream.rdbuf()->available() < 6)
      {
        std::this_thread::sleep_for(std::chrono::seconds(1));
      }

      // Read 1 byte out of the 6 avaialble.
      std::array<char, 6> actual_data{};
      auto bytes_transferred = readsome(stream, begin(actual_data), 1);
      assert(bytes_transferred == 1);
      assert(std::equal(
        begin(actual_data),
        begin(actual_data) + bytes_transferred,
        begin(expected_data)));

      // Attempt to read 6 bytes, although only 5 are available.
      bytes_transferred = readsome(stream, begin(actual_data),
                                   sizeof actual_data);
      assert(bytes_transferred == 5);
      assert(std::equal(
        begin(actual_data),
        begin(actual_data) + bytes_transferred,
        begin(expected_data) + 1));

      // Attempt to read 6 more bytes, even though 0 bytes are available.
      bytes_transferred = readsome(stream, begin(actual_data),
                                   sizeof actual_data);
      assert(bytes_transferred == 0);
    });

  // Connect the sockets then write to the stream.
  acceptor.accept(socket);
  boost::asio::write(socket, boost::asio::buffer(expected_data));

  // Wait for the stream to complete.
  client_thread.join();
}

<子> 1。 tcp::stream文档及其相关类没有详细记录。我不知道这种行为是故意的,是一种错误,还是仅仅被忽视了。在当前的networking-ts draft

中,文档仍然相当简洁