当我失去连接时,在我的服务器代码中,我尝试永远重新连接循环。重新连接后,我会向我连接的组件发送登录消息。该组件然后发回一个看起来像“MyResponse”的登录响应
初始连接正常。然而,在我重新连接之后,我在预期的消息之前得到了垃圾,看起来像是:“ýMyResponse”
谷歌搜索后。我在Stack Overflow上看到很多关于boost :: asio :: streambuf的问题,它用于boost :: asio中的异步套接字。特别是关于重用他的缓冲区。我遵循了那里的建议并在断开连接时调用了消耗。换句话说,我在调用shutdown并关闭我的套接字之后调用boost :: asio :: streambuf :: consume,之后在recv上调用了一个错误以响应对recv_until的调用。
我还使用wireshark来确保垃圾字符没有被发送,而不是。
经过大量调试后,似乎消耗的调用是注入一个字符而不是清除所有字符。
这是一个最小的例子:
#include <boost/asio.hpp>
#include <iostream>
#include <sstream>
#include <string>
int main()
{
boost::asio::streambuf buffer;
std::cout << "buffer size " << buffer.size() << std::endl;
buffer.consume(std::numeric_limits<size_t>::max());
std::cout << "buffer size " << buffer.size() << std::endl;
std::istream is(&buffer);
std::string contents;
is >> contents;
std::cout << "Contents: " << contents << std::endl;
std::cout << "buffer size " << buffer.size() << std::endl;
return 0;
}
输出:
buffer size 0
buffer size 1
Contents: ²
buffer size 0
预期产出:
buffer size 0
buffer size 0
Contents:
buffer size 0
如果我不使用消费,在我的服务器代码中,在重新连接后的第一条消息之前,我会收到一些断开连接的消息。
如果我使用消费,我会得到一个垃圾字符。
请参阅:
Working with boost::asio::streambuf
答案 0 :(得分:1)
ý
字符表示调试堆memory fence:
这意味着streambuf指针已损坏。
我没有全面了解您的程序,但我注意到您没有正确地同步套接字上的写入/读取。
例如,查看MyClass::Send
,它会附加到现有 m_sendBuffer
,但会使用async_write
再次发送所有 。这是
m_sendBuffer
中已存在任何意味着async_write
已经启动的内容未定义的行为,因为the docs说:
此操作是根据对流的
async_write_some
函数的零次或多次调用实现的,并且称为组合操作。程序必须确保流不执行其他写操作(例如async_write
,流的async_write_some
函数或执行写操作的任何其他组合操作),直到此操作完成。
数据竞赛:m_sendBuffer
正在修改,而之前的写入操作可能是航班
解决此问题的常用方法是拥有一个传出缓冲区队列,而不是一个缓冲区,并连续发送它们,例如: boost asio async_write : how to not interleaving async_write calls?
在这里,我没有积极发现任何其他问题。发送方面的相同问题仍然适用。
一旦您有了未定义的行为,您就会发现任何行为,因此也会影响接收行为。
最重要的是,读取循环导致m_socket
上存在数据争用:Send
在服务线程上运行async_read循环时从ProcessingThreadProc
触发m_socket
)。
tcp::socket
io_service
类不是线程安全的。因为您有一个工作线程以及运行m_socket
的线程(因此也就是完成处理程序),所以如果没有同步,您将无法访问strand
。
您应该使用m_socket
序列化共享对象m_socket
上的操作。在这种情况下,对m_strand.post([this] {
auto callback = boost::bind(&MyClass::OnSend, this, boost::asio::placeholders::error);
async_write(m_socket, m_sendBuffer, m_strand.wrap(callback));
});
的访问在该链上运行的完成处理程序中已经是安全的。所有其他访问都应发布到链,例如:
m_numPostedSocketIO
实际上,可以使用strand来同步对
m_numPostedSocketIO
变量的访问,但这会删除读/写操作的全双工能力。此外,您不需要boost::asio::error::operation_aborted
计数器:
请注意,关闭套接字确实已取消所有挂起的异步IO操作。他们将填写错误代码m_socket
。
这意味着您可以简化等待挂起IO操作完成的部分。您只需关闭套接字即可。注意:
阻止对m_strand.post([this] { m_socket.close(); }); // e.g.
的不同步访问,在帖子上发布:
apply plugin: 'kotlin-kapt'
android {
...
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
main.java.srcDirs += [file("$buildDir/generated/source/kapt/main")]
}
...
}
...
compile "com.google.dagger:dagger:2.12"
...
kapt "android.arch.persistence.room:compiler:1.0.0-beta1"
kapt "com.google.dagger:dagger-compiler:2.12"
kapt "com.android.databinding:compiler:2.3.3"
答案 1 :(得分:1)
boost :: asio :: streambuf :: consume overflows。
使用
buffer.consume(buffer.consume(buffer.size());
而不是
buffer.consume(std::numeric_limits<size_t>::max());
报告错误以提升邮件列表。