Heisenbug从套接字进行同步读取时

时间:2016-10-26 13:06:12

标签: c++ sockets c++11 boost-asio

我在域套接字上调用async_read,我的问题是有时我得到数据,有时候我没有,即使远程系统总是返回数据。如果我一步一步地调试,我似乎能够从套接字读取。如果我自动化单元测试,它们似乎运行得太快而无法返回数据,这很奇怪,因为异步方法的整个目的是等待回复。

我将这些作为我班级的属性:

io_service run_loop;
stream_protocol::socket connection_socket;
datagram_protocol::endpoint domain_socket_ep;
vector<unsigned char>read_buffer;

我写一下:

void operator>>(const vector<unsigned char> input, shared_ptr<Socket>socket) {
  asio::async_write(socket->connection_socket, asio::buffer(input),   std::bind(&Socket::write_handler, socket, std::placeholders::_1, std::placeholders::_2));
  socket->run_loop.reset();
  socket->run_loop.run();
}

在写回调中,我做了一个阅读:

void Socket::write_handler(const std::error_code &ec, const size_t size) noexcept {
  const size_t avail = connection_socket.available();
  if (!read_buffer.empty()) {
    read_buffer.clear();
  }
  asio::async_read(connection_socket, asio::buffer(read_buffer, avail), std::bind(&Socket::read_handler, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}

我尝试在while(read_buffer.size() < avail)中包装read函数,但这只会让我陷入无限循环。

我肯定在这里遗漏了一些东西,我只是无法弄清楚什么以及在逐步运行时这种情况有效的事实会使情况变得更糟。

1 个答案:

答案 0 :(得分:4)

在阅读方面:

你永远不会提到read_buffer的类型。我们对.clear()的作用并不是很了解,但如果它符合名称的建议,那么在没有事先asio::buffer(read_buffer, avail)

的情况下使用read_buffer.resize(avail)将无效

为什么有

void operator>>(const vector<unsigned char> input, shared_ptr<Socket>socket) {
  asio::async_write(socket->connection_socket, asio::buffer(input),   std::bind(&Socket::write_handler, socket, std::placeholders::_1, std::placeholders::_2));
  socket->run_loop.reset();
  socket->run_loop.run();
}

而不是例如

void operator>>(const std::vector<unsigned char> input, std::shared_ptr<Socket> socket) {
    boost::system::error_code ec;
    size_t transferred = boost::asio::write(socket->connection_socket, boost::asio::buffer(input), ec);
    socket->write_handler(ec, transferred);
}

如果您不想进行异步操作,请不要使用它们。这至少要简单得多。以下示例将是合理的(如果您确保io的寿命比使用它的任何套接字长):

<强> Live On Coliru

#include <boost/asio.hpp>

struct Socket {
    boost::asio::io_service& svc;
    boost::asio::ip::tcp::socket connection_socket;

    Socket(boost::asio::io_service& svc) : svc(svc), connection_socket(svc) {}

    void write_handler(boost::system::error_code ec, size_t bytes_transferred) {
    }
};

void operator>>(const std::vector<unsigned char> input, std::shared_ptr<Socket> socket) {
    boost::system::error_code ec;
    size_t transferred = boost::asio::write(socket->connection_socket, boost::asio::buffer(input), ec);
    socket->write_handler(ec, transferred);
}

int main(){
    boost::asio::io_service io;
    auto s = std::make_shared<Socket>(io);

    std::vector<unsigned char> v { 100, 'a' };
    v >> s;
}