提升async_read_until结合match_condition与限制大小以读取 [英] boost async_read_until combine match_condition with limit size to read

查看:81
本文介绍了提升async_read_until结合match_condition与限制大小以读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有办法组合读取两个条件,直到找到匹配的字符或接收到128个字节?

Is there way to combain two conditions read until a matching character is found or 128 bytes received?

可以限制streambuf大小:

It is possible to limit streambuf size:

inBuf = std::make_shared< boost::asio::streambuf>(limit_size);

但是当处理程序的原因为找不到元素"时,流中没有可用数据,并且传输的字节也为0.

But when handler with reason "Element not found" there is no available data in stream and transferred bytes also is 0.

这个想法是读到';'或接收到128个字节

The idea is to read until ';' or 128 bytes received

我的代码如下:

class match_char
{
public:
  explicit match_char(char c, int len) : c_(c), len_(len) {}

  template <typename Iterator>
  std::pair<Iterator, bool> operator()(
      Iterator begin, Iterator end) const
  {
    Iterator i = begin;

    const size_t buffer_len = std::distance(begin,end); <-- this is not work usualy distance here is 1

    if(buffer_len >= len_)
    {
      std::advance(i, len_);
      return std::make_pair(i, true);
    }

    while (i != end)
      if (c_ == *i++) {
        return std::make_pair(i, true);
      }
    return std::make_pair(i, false);
  }

private:
  char c_;
  int len_;
};

namespace boost {
    namespace asio {
      template <> struct is_match_condition<match_char>
      : public boost::true_type {};
    }
}


boost::asio::streambuf b;

void main() {

boost::asio::async_read_until(port, b,
           match_char(';', 128) , &handler);

           }

推荐答案

自定义MatchCondition条件不允许将从流中读取的字节数限制为不超过n字节数. read_until()系列函数均允许将超出定界符的数据从Stream中读取到streambuf中.本质上,read_until()将从streambuf准备一个缓冲区,从Stream读取一大块数据到准备好的缓冲区中,然后使用MatchCondition检查是否满足完成条件.

A custom MatchCondition condition will not allow one to limit the number of bytes read from the stream to not exceed n number of bytes. The read_until() family of functions all allow for data beyond the delimiter to be read from the Stream and into the streambuf. In essence, read_until() will prepare a buffer from the streambuf, read a chunk of data from Stream into the prepared buffer, then use the MatchCondition to check if the completion conditions have been met.

为了读取不超过n个字节并在找到所需的分隔符时尽早完成操作,请考虑构造

In order to read no more than n bytes and complete early if a desired delimiter is found, consider constructing the boost::asio::streambuf with a max size, and then using the read_until() operations. For example, the following will read no more than 128 bytes from the stream and complete early if the ';' delimiter is found:

boost::asio::streambuf buffer(128);
boost::system::error_code error;
std::size_t bytes_transferred = boost::asio::read_until(
    stream, buffer, ';', error);

在上面的示例中

  • 如果读取了128个字节并且未找到分隔符,则error将是boost::asio::error::not_found,而buffer.size()将是128.
  • 如果找到了定界符,则error将成功执行,而bytes_transferred将是直到buffer的输入序列之内的定界符(包括该定界符)为止的字节数.请注意,buffer.size()可能大于bytes_transferred,但不会超过128.
  • 如果未读取128字节且未找到分隔符,则error将包含有关读取操作失败原因的适当错误条件,例如boost::asio::error::eof如果远程对等方关闭了连接./li>
  • If 128 bytes were read and the delimiter was not found, then error will be boost::asio::error::not_found and buffer.size() will be 128.
  • If the delimiter was found, then error will be successful and bytes_transferred will be the number of bytes up to and including the delimiter that reside within the buffer's input sequence. Note that buffer.size() may be larger than bytes_transferred, but will not exceed 128.
  • If 128 bytes were not read and a delimiter was not found, then error will contain the appropriate error condition as to why the read operation failed, such as boost::asio::error::eof if the remote peer closed the connection.

这是一个完整的示例演示 streambuf的行为:

Here is a complete example demonstrating the behavior of streambuf:

#include <iostream>
#include <thread>
#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() {}

std::string make_string(boost::asio::streambuf& streambuf, std::size_t n)
{
 return {buffers_begin(streambuf.data()),
         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();

  // Write data to server that contains a delimiter.
  auto bytes_written = boost::asio::write(server_socket,
      boost::asio::buffer(std::string("12345;67890")));

  // Wait for all data to be received.
  while (bytes_written != client_socket.available())
  {
    std::this_thread::sleep_for(std::chrono::seconds(1));
  }

  // Create a streambuf too small to read up to the delimter.
  {
    const std::size_t MAX_SIZE = 2;
    boost::asio::streambuf read_buffer(MAX_SIZE);

    boost::system::error_code error;
    auto bytes_read = boost::asio::read_until(
        client_socket, read_buffer, ';', error);

    // Expect an error as the delim was not found, so the read_until
    // return value is 0.  However, data was read into the buffer.
    assert(boost::asio::error::not_found == error);
    assert(bytes_read == 0);
    assert(read_buffer.size() == 2); // "12" out of "12345;67890";

    // Verify additional data was not read from the stream.
    assert((bytes_written - MAX_SIZE) == client_socket.available());
  }

  // Default construct a streambuf, which has a large max.
  {
    boost::asio::streambuf read_buffer;

    // Read from the socket.
    boost::system::error_code error;
    auto bytes_read = boost::asio::read_until(
        client_socket, read_buffer, ';', error);

    // Verify that at least "345;" was read.
    assert(!error);
    assert(bytes_read != 0);
    assert(make_string(read_buffer, bytes_read) == "345;");

    // Not a guarantee, but the implementation may (and likely will)
    // read beyond the delimiter.  If so, the streambuf's size will
    // be larger than return value from read_until, as it returns the
    // number of bytes up to and including the delimiter.
    if (bytes_read < read_buffer.size())
    {
      std::cout << "Read beyond delimiter" << std::endl;
    }
  }

  std::cout << "bytes remaining: " << client_socket.available() <<
               std::endl;
}

输出:

Read beyond delimiter
bytes remaining: 0

这篇关于提升async_read_until结合match_condition与限制大小以读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆