我一直在尝试从http://think-async.com/asio/boost_asio_1_3_0/doc/html/boost_asio/example/http/server/connection.cpp开始并根据我的需要进行修改。我希望一个接一个地接受多个客户端,最终通过TCP读取数据。如果我运行它,然后在另一个shell中使用
,我的服务器工作正常nc localhost 3731
然后点击控制-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 ControlServer\n";
}
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;
}
答案 0 :(得分:2)
您有两个io_service实例。行为的差异来自于在两个不同的io_service实例初始化的套接字上调用async_accept的事实。混淆来自于您将参数io_service_命名为与成员变量相同的方式。我设法通过使成员变量成为引用来修复代码。
/// The io_service used to perform asynchronous operations. 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。
// The io_service object provides I/O services, such as sockets, // that the server object will use. ControlServer server(CONTROL_BIND_ADDRESS, CONTROL_PORT); // Run the io_service object to perform asynchronous operations. server.io_service().run();
我希望这是有道理的,我上周第一次只使用了boost :: asio,写了类似的东西。
https://dabblingseriously.wordpress.com/2015/07/06/a-minimal-http-web-server-using-boostasio/