提升async_read_until结合match_condition与限制大小以读取 [英] boost async_read_until combine match_condition with limit size to read
问题描述
是否有办法组合读取两个条件,直到找到匹配的字符或接收到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, thenerror
will beboost::asio::error::not_found
andbuffer.size()
will be128
. - If the delimiter was found, then
error
will be successful andbytes_transferred
will be the number of bytes up to and including the delimiter that reside within thebuffer
's input sequence. Note thatbuffer.size()
may be larger thanbytes_transferred
, but will not exceed128
. - If
128
bytes were not read and a delimiter was not found, thenerror
will contain the appropriate error condition as to why the read operation failed, such asboost::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屋!