下面的代码片段可以在这个页面看到。
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace boost::asio;
using ip::tcp;
using std::cout;
using std::endl;
class con_handler : public boost::enable_shared_from_this<con_handler>
{
private:
tcp::socket sock;
std::string message="Hello From Server!";
enum { max_length = 1024 };
char data[max_length];
public:
typedef boost::shared_ptr<con_handler> pointer;
con_handler(boost::asio::io_service& io_service)
: sock(io_service)
{
}
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new con_handler(io_service));
}
tcp::socket& socket()
{
return sock;
}
void start()
{
sock.async_read_some(
boost::asio::buffer(data, max_length),
boost::bind(&con_handler::handle_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
sock.async_write_some(
boost::asio::buffer(message, max_length),
boost::bind(&con_handler::handle_write,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_read(const boost::system::error_code& err,
size_t bytes_transferred)
{
if (!err) {
cout << data << endl;
} else {
std::cerr << "err (recv): " << err.message() << std::endl;
sock.close();
}
}
void handle_write(const boost::system::error_code& err,
size_t bytes_transferred)
{
if (!err) {
cout << "Server sent Hello message!"<< endl;
} else {
std::cerr << "err (recv): " << err.message() << std::endl;
sock.close();
}
}
};
class Server {
private:
tcp::acceptor acceptor_;
void start_accept()
{
// creates a socket
con_handler::pointer connection =
con_handler::create(acceptor_.get_io_service());
// initiates an asynchronous accept operation
// to wait for a new connection.
acceptor_.async_accept(connection->socket(),
boost::bind(&Server::handle_accept, this, connection,
boost::asio::placeholders::error));
}
public:
Server(boost::asio::io_service& io_service): acceptor_(io_service, tcp::endpoint(tcp::v4(), 1234))
{
start_accept();
}
void handle_accept(con_handler::pointer connection,
const boost::system::error_code& err)
{
if (!err) {
connection->start();
}
start_accept();
}
};
int main(int argc, char *argv[])
{
try
{
boost::asio::io_service io_service;
Server server(io_service);
io_service.run();
}
catch(std::exception& e)
{
std::cerr << e.what() << endl;
}
return 0;
}
我认为代码片段应该改进。 由于
asio::placeholders::error
相当于 placehodlers::_1
并且 const boost::system::error_code& err
是 void Server::handle_accept(con_handler::pointer connection, const boost::system::error_code& err)
的第二个参数,因此在下面的代码中 boost::asio::placeholders::error
应替换为 boost::placeholders::_2
。
acceptor_.async_accept(connection->socket(),
boost::bind(&Server::handle_accept, this, connection,
boost::asio::placeholders::error));
如果您正在考虑参数 (_1) 的位置,那么它是正确的,因为处理程序签名是 (docs):
void handler(
const boost::system::error_code& error // Result of operation.
);
请注意,bind 表达式 是您的处理程序,而不是
handle_accept
(它需要 3 个参数,包括 this 参数)。
如果您认为
_1
更具表现力,那就去吧。
同时,
<boost/bind/bind.hpp>
或配置编译器定义)bytes_transferred
);特别是不要依赖 data
的 NUL 终止!using namespace
const&
handle_XYZ
设为私有sock.close()
;您可以取消任何异步操作链并让 con_handler
的析构函数处理它。在您的情况下,即使 cancel
也是多余的,因为没有异步循环,并且单个读/写已经失败简化到这一点:Live On Coliru
#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
namespace asio = boost::asio;
using namespace std::placeholders;
using asio::ip::tcp;
struct con_handler : std::enable_shared_from_this<con_handler> {
using pointer = std::shared_ptr<con_handler>;
con_handler(asio::any_io_executor ex) : sock(ex) {}
tcp::socket& socket() { return sock; }
void start() {
auto self = shared_from_this();
sock.async_read_some(asio::buffer(data), bind(&con_handler::handle_read, self, _1, _2));
sock.async_write_some(asio::buffer(message), bind(&con_handler::handle_write, self, _1, _2));
}
private:
void handle_read(boost::system::error_code const& err, size_t bytes_transferred) {
std::cerr << "recv: " << bytes_transferred << "(" << err.message() << ")" << std::endl;
if (!err) {
std::string_view msg(data.data(), bytes_transferred);
std::cout << quoted(msg) << std::endl;
}
// else sock.cancel();
}
void handle_write(boost::system::error_code const& err, size_t bytes_transferred) {
std::cerr << "sent: " << bytes_transferred << "(" << err.message() << ")" << std::endl;
if (!err)
std::cout << "Server sent " << quoted(message) << std::endl;
// else sock.cancel();
}
tcp::socket sock;
std::string message = "Hello From Server!";
std::array<char, 1024> data;
};
struct Server {
Server(asio::any_io_executor ex) //
: acceptor_(ex, tcp::endpoint(tcp::v4(), 1234)) {
start_accept();
}
void handle_accept(con_handler::pointer connection, boost::system::error_code const& err) {
if (!err)
connection->start();
start_accept();
}
private:
tcp::acceptor acceptor_;
void start_accept() {
con_handler::pointer connection = std::make_shared<con_handler>(acceptor_.get_executor());
acceptor_.async_accept(connection->socket(), bind(&Server::handle_accept, this, connection, _1));
}
};
int main() try {
asio::io_context ioc;
Server server(ioc.get_executor());
ioc.run();
} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
}
本地演示:
Asio版本:get_io_service()表示boost的古老版本
io_service
引用,传递执行器,使代码耦合更少,更容易维护new
,支持 make_shared
async_accept
的移动接受重载,这样你就不必违反 socket() { return sock; }
文本协议:
read_some
。例如。决定按行 IO,因此您可以读取直到第一个换行符(并且还可以使用换行符终止符写入消息)#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
namespace asio = boost::asio;
using namespace std::placeholders;
using asio::ip::tcp;
struct con_handler : std::enable_shared_from_this<con_handler> {
con_handler(tcp::socket s) : sock(std::move(s)) {}
void start() {
auto self = shared_from_this();
do_read();
async_write(sock, asio::buffer(message), //
bind(&con_handler::handle_write, self, _1, _2));
}
private:
void do_read() {
async_read_until(sock, asio::dynamic_buffer(response), "\n",
bind(&con_handler::handle_read, shared_from_this(), _1, _2));
}
void handle_read(boost::system::error_code const& err, size_t bytes_transferred) {
std::cerr << "recv: " << bytes_transferred << "(" << err.message() << ")" << std::endl;
if (!err) {
auto msg = response.substr(0, bytes_transferred - 1);
response.erase(0, bytes_transferred);
std::cout << quoted(msg) << std::endl;
do_read();
}
// else sock.cancel();
}
void handle_write(boost::system::error_code const& err, size_t bytes_transferred) {
std::cerr << "sent: " << bytes_transferred << "(" << err.message() << ")" << std::endl;
if (!err)
std::cout << "Server sent " << quoted(message) << std::endl;
// else sock.cancel();
}
tcp::socket sock;
std::string message = "Hello From Server!\n", response;
};
struct Server {
Server(asio::any_io_executor ex) : acceptor_(ex, tcp::endpoint(tcp::v4(), 1234)) { accept_loop(); }
private:
tcp::acceptor acceptor_;
void accept_loop() {
acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket s) {
if (!ec)
std::make_shared<con_handler>(std::move(s))->start();
accept_loop();
});
}
};
int main() try {
asio::io_context ioc;
Server server(ioc.get_executor());
ioc.run();
} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
}
有更实用的本地演示: