我正在使用boost.asio实现一个网络库。这是一个TCP类的读取函数。
我的一个测试案例有一个客户端连接到服务器,一旦握手完成,服务器立即用delimeter背靠背发送两条消息。客户端读取第一条消息,但不读取第二条。如果稍后发送第三条消息,它将拾取第二条丢失的消息。bytes变量仅为一条消息的长度。这里有什么令人不安的错误吗?
(我删除了不相关的代码)
boost::asio::streambuf _recBuf;
ssl::stream<ip::tcp::socket&> _stream;
void SomeClass::read(const String &delim) {
boost::asio::async_read_until(_stream, _recBuf, delim,
boost::asio::bind_executor(_readStrand,
[this, delim, self = shared_from_this()] (const boost::system::error_code& ec, const std::size_t bytes) {
if (!ec) {
if (bytes <= delim.size()) {
return;
}
String data(boost::asio::buffers_begin(_recBuf.data()), boost::asio::buffers_begin(_recBuf.data()) + (bytes - delim.size()));
_recBuf.consume(bytes);
read(delim);
}
else if (ec == system::errc::operation_canceled) {
}
else {
}
}));
}
字符串
我尝试使用commit()方法和istream来改变读取_recBuf的方式。
调用available()方法on _stream.lowest_layer()查看客户端上有多少字节可用于等待这两个背靠背的消息,在读取初始消息后返回0。
编辑
下面是write方法。也许这会导致问题?
void TCPSBase::write(const Message &msg) {
String data = msg.toJsonStr() + '^';
asio::async_write(_stream, asio::buffer(data),
asio::bind_executor(_writeStrand,
[this, data, self = shared_from_this()] (const boost::system::error_code& ec, const std::size_t bytes) {
LogHandler lh(Logger::getInstance(), "TCPSBase::write::lambda");
if (!ec) {
lh.d("wrote " + std::to_string(bytes) + " bytes");
lh.d(data);
}
else if (ec == system::errc::operation_canceled) {
lh.d("canceled");
}
else {
lh.e("disconnecting after error during write: " + ec.message());
stop();
}
}));
型
}
1条答案
按热度按时间ycggw6v21#
调用available()方法on _stream.lowest_layer()查看有多少字节可用会导致错误的文件描述符异常。
这意味着套接字变得无效,例如,因为它被关闭。
为了检查问题的其余部分,我使用BARE最小代码使您的代码自包含:
Live On Coliru
字符串
使用
server.pem
和客户端型
精确显示预期的
型
任何剩下的批评都将是
bind_executor
,它比首先将套接字与串相关联要差(在我的代码中,我已经这样做了,所以会话类(SomeClass
)中的整个串都是冗余的)asio::error::operation_aborted
或实际上对应的error_condition
,如果可用(阅读这里了解更多:测试特定的错误条件)bytes <= delim.size()
时,静默地中断读循环(以及可能的连接)。当客户端发送空消息时,这看起来像“刚刚挂断”。