Boost::asio async_read_some工作一次,然后停止工作,为什么?(要查看使用)

boost::asio async_read_some works once then stops working, why? (uses shared_ptr)

本文关键字:为什么 停止工作 然后 async asio 工作 some 一次 Boost read      更新时间:2023-10-16

我一直在尝试从http://think-async.com/asio/boost_asio_1_3_0/doc/html/boost_asio/example/http/server/connection.cpp开始并修改它以满足我的需求。我想一个接一个地接受多个客户端,并最终通过TCP读取数据。我的服务器工作正常,如果我运行它,然后在另一个shell中使用

nc localhost 3731

然后按control-C。第一个客户机已正确断开连接。然后再次输入相同的命令。麻烦来了下一个客户;它接受并打印出读取好的开始,但是当我在第二个客户端上点击control-C时,它似乎没有得到断开连接的消息。我不知道为什么。boost::asio async_read_some有什么帮助吗?

下面是输出调试消息,显示第一个客户端工作,然后后续客户端没有正确断开连接:

./a.out                                                          
Made connection       at address 80x2240370
Added connection to ConnectionManager at 80x2240370
  Starting read at address 80x2240370
Made connection       at address 80x22449f0
Did read of 0 with error code asio.misc:2
Accepting bytes.
Removing connection to ConnectionManager at 80x2240370
Destroying connection at address 80x2240370
Added connection to ConnectionManager at 80x22449f0
  Starting read at address 80x22449f0
Made connection       at address 80x2248af0

下面是完整的源代码,为了简洁而编辑,但仍然显示了问题:

// compile with: g++ asiohelp.cpp -lboost_system -lpthread  -std=c++11
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <set>
#include <vector>
#include <string>
#define CONTROL_PORT "3731"
#define CONTROL_BIND_ADDRESS "127.0.0.1"
namespace hsd {
namespace net {
class HSDConnectionManager;
class HSDConnection: public boost::enable_shared_from_this<HSDConnection> {
  boost::asio::ip::tcp::socket socket_;
  boost::array<char, 16384> readBuffer_;
  HSDConnectionManager& connectionManager_;
public:
  explicit HSDConnection(boost::asio::io_service& io_service,
      HSDConnectionManager& manager);
  ~HSDConnection(void);
  boost::asio::ip::tcp::socket& socket(void);
  /// Start the first asynchronous operation for the connection.
  void startRead(void);
  void handleRead(const boost::system::error_code& e,
      std::size_t bytesTransferred);
  void stop(void);
private:
  void continueRead(void);
};
typedef boost::shared_ptr<HSDConnection> ConnectionPtr;
}
}

namespace hsd {
namespace net {
class HSDConnectionManager: private boost::noncopyable {
public:
  void start(ConnectionPtr c);
  void stop(ConnectionPtr c);
  void stop_all();
private:
  std::set<ConnectionPtr> connections_;
};
}
}
namespace hsd {
namespace net {
class ControlServer {
public:
  // Construct the server to listen on the specified TCP address and port
  explicit ControlServer(boost::asio::io_service& io_service_,
      const std::string& address, const std::string& port);
  virtual ~ControlServer(void);
  // Run the server's io_service loop.
  void run();
  // Stop the server.
  void stop();
  // Handle packet
  virtual void packetReceived(std::string result);
private:
  /// Handle completion of an asynchronous accept operation.
  void handleAccept(const boost::system::error_code& e);
  /// Handle a request to stop the server.
  void handleStop();
  /// The io_service used to perform asynchronous operations.
  boost::asio::io_service io_service_;
  /// Acceptor used to listen for incoming connections.
  boost::asio::ip::tcp::acceptor acceptor_;
  /// The connection manager which owns all live connections.
  HSDConnectionManager connectionManager_;
  /// The next connection to be accepted.
  ConnectionPtr nextConnection_;
};
}
}

using namespace std;
using namespace boost::system::errc;
namespace hsd {
namespace net {
ControlServer::ControlServer(boost::asio::io_service& io_service_,
    const std::string& address, const std::string& port) :
    io_service_(), acceptor_(io_service_), connectionManager_(), nextConnection_() {
  nextConnection_ = ConnectionPtr(
      new HSDConnection(io_service_, connectionManager_));
  // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
  boost::asio::ip::tcp::resolver resolver(io_service_);
  boost::asio::ip::tcp::resolver::query query(address, port);
  boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
  acceptor_.open(endpoint.protocol());
  acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
  acceptor_.bind(endpoint);
  acceptor_.listen();
  acceptor_.async_accept(nextConnection_->socket(),
      boost::bind(&ControlServer::handleAccept, this,
          boost::asio::placeholders::error));
}
ControlServer::~ControlServer(void) {
  cout << "Destroying ControlServern";
}
void ControlServer::handleAccept(const boost::system::error_code& e) {
  if (e == success) {
    connectionManager_.start(nextConnection_);
    nextConnection_.reset(
        new HSDConnection(io_service_, connectionManager_));
    //nextConnection_ = ConnectionPtr(new HSDConnection(io_service_,
    //             connectionManager_, *hsPacketReaderListener_s));
    acceptor_.async_accept(nextConnection_->socket(),
        boost::bind(&ControlServer::handleAccept, this,
            boost::asio::placeholders::error));
  }
}
void ControlServer::packetReceived(std::string result) {
  cout << "Got packet: " << result << "n";
}
}
}

using namespace std;
namespace hsd {
namespace net {
boost::asio::ip::tcp::socket& HSDConnection::socket(void) {
  return socket_;
}
HSDConnection::HSDConnection(boost::asio::io_service& io_service,
    HSDConnectionManager& manager) :
    socket_(io_service), connectionManager_(manager), readBuffer_()
{
  cout << "Made connection       at address " << ios::hex << this << "n";
}
HSDConnection::~HSDConnection(void) {
  cout << "Destroying connection at address " << ios::hex << this << "n";
}
void HSDConnection::handleRead(const boost::system::error_code& e,
    std::size_t bytesTransferred) {
  cout << "Did read of " << bytesTransferred << " with error code " << e
      << "n";
  std::string byteString(readBuffer_.data(), bytesTransferred);
  vector<string> result;
  cout << "Accepting bytes.n";
  //hsPacketCore_.acceptBytes(byteString, result);
  for (string &packet : result) {
    //listener_->packetReceived(packet);
  }
  if (e == boost::system::errc::success
      || e == boost::asio::error::operation_aborted) {
    continueRead();
  } else if (bytesTransferred == 0) {
    connectionManager_.stop(shared_from_this());
  }
}
void HSDConnection::continueRead(void) {
  cout << "Continuing read at address " << ios::hex << this << "n";
  socket_.async_read_some(boost::asio::buffer(readBuffer_),
      boost::bind(&HSDConnection::handleRead, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
}
void HSDConnection::startRead(void) {
  cout << "  Starting read at address " << ios::hex << this << "n";
  socket_.async_read_some(boost::asio::buffer(readBuffer_),
      boost::bind(&HSDConnection::handleRead, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
}
void HSDConnection::stop(void) {
  socket_.close();
}
}
}
namespace hsd {
namespace net {
void HSDConnectionManager::start(ConnectionPtr c) {
  connections_.insert(c);
  std::cout << "Added connection to ConnectionManager at " << std::ios::hex << c
      << "n";
  c->startRead();
}
void HSDConnectionManager::stop(ConnectionPtr c) {
  std::cout << "Removing connection to ConnectionManager at " << std::ios::hex
      << c << "n";
  connections_.erase(c);
  c->stop();
}
}
}

using boost::asio::ip::tcp;
using namespace std;
using namespace hsd::net;
int main()
{
  try
  {
    // We need to create a server object to accept incoming client connections.
    boost::asio::io_service io_service;
    // The io_service object provides I/O services, such as sockets,
    // that the server object will use.
    ControlServer server(io_service, CONTROL_BIND_ADDRESS, CONTROL_PORT);
    // Run the io_service object to perform asynchronous operations.
    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
  return 0;
}

您有两个io_service实例。行为上的区别在于,您在从两个不同的io_service实例初始化的套接字上调用async_accept。这种混淆来自于将参数io_service_命名为与成员变量相同的方式。我设法通过使成员变量为引用来修复您的代码。

<>之前///执行异步操作的io_service。boost:: asio: io_service& io_service_;之前

,然后在构造函数的形式形参中消除变量的歧义,并用该形参初始化成员变量。

<>之前ControlServer:: ControlServer (boost:: asio: io_service& io_service,Const std::string& address, Const std::string& port):io_service_ (io_service) acceptor_ (io_service),connectionManager_(), nextConnection_() {之前

另一个选项是公开io_service成员变量,然后运行该io_service。

<>之前//io_service对象提供I/O服务,例如socket;//服务器对象将使用的。ControlServer server(CONTROL_BIND_ADDRESS, CONTROL_PORT);//运行io_service对象执行异步操作。.run server.io_service () ();之前

我希望这是有意义的,我上周才第一次使用boost::asio,写了一个类似的东西