如何创建监听两个不同端口的 boost::asio 服务器
how to create boost::asio server that listen to two different ports
我正在使用 boost 1.75.0 并且正在尝试更新我的服务器以便他可以同时收听两个不同的端口
假设 IP 127.0.0.1 port 6500 and port 6600.
我需要保持 Server
两个插座吗?
这是我的服务器
#include <boost/asio/io_service.hpp>
#include <boost/asio.hpp>
#include <queue>
#include "Session.h"
using boost::asio::ip::tcp;
class Server
{
public:
Server(boost::asio::io_service &io_service, short port)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
socket_(io_service)
{
do_accept();
}
private:
void do_accept(){
acceptor_.async_accept(socket_,
[this](boost::system::error_code ec) {
if (!ec) {
std::cout << "accept connection\n";
std::make_shared<Session>(std::move(socket_))->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
tcp::socket socket_;
};
这是我的会话class
#include <boost/asio/io_service.hpp>
#include <boost/asio.hpp>
#include "message.h"
#include <fstream>
#include <boost/bind/bind.hpp>
namespace {
using boost::asio::ip::tcp;
auto constexpr log_active=true;
using boost::system::error_code;
using namespace std::chrono_literals;
using namespace boost::posix_time;
};
class Session
: public std::enable_shared_from_this<Session>
{
public:
Session(tcp::socket socket)
: socket_(std::move(socket)) ,
{
}
~Session()= default;
void start();
void do_write_alive();
private:
void do_read_header();
void do_read_body();
void do_write();
using Strand = boost::asio::strand<tcp::socket::executor_type>;
using Timer = boost::asio::steady_timer;
tcp::socket socket_{strand_};
Strand strand_{make_strand(socket_.get_executor())};
Timer recv_deadline_{strand_};
Timer send_deadline_{strand_};
enum { max_length = 1024 };
char data_[max_length];
};
我没有包括 Session
class 只有构造函数的实现,因为那里不相关。
你需要两个受体。
您可以不使用 socket_ 实例,同时删除重复项。
这是一个最小的重构,运行s 10 个监听器,存储在双端队列中(为了参考稳定性):
class Server {
public:
Server(boost::asio::io_service& svc, uint16_t base_port) {
for (uint16_t port = base_port; port < base_port + 10; ++port) {
auto& a = acceptors_.emplace_back(svc, tcp::endpoint{{}, port});
a.listen();
accept_loop(a);
}
}
void stop() {
for (auto& a: acceptors_)
a.cancel();
}
private:
static void accept_loop(tcp::acceptor& a) {
a.async_accept(a.get_executor(), [&a](error_code ec, tcp::socket&& s) {
if (!ec) {
std::cout << "accepted " << s.remote_endpoint() << " on :" << a.local_endpoint().port() << std::endl;
std::make_shared<Session>(std::move(s))->start();
accept_loop(a);
} else {
std::cout << "exit accept_loop " << ec.message() << std::endl;
}
});
}
std::deque<tcp::acceptor> acceptors_;
};
使用io_context
和执行器
您可以使用执行器模型对其进行更多现代化改造:
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/bind/bind.hpp>
#include <fstream>
#include <deque>
namespace {
using boost::asio::ip::tcp;
//auto constexpr log_active = true;
using boost::system::error_code;
using namespace std::chrono_literals;
//using namespace boost::posix_time;
} // namespace
class Session : public std::enable_shared_from_this<Session> {
public:
Session(tcp::socket socket) : socket_(std::move(socket)) {}
~Session() = default;
void start() {}
void do_write_alive() {}
private:
void do_read_header() {}
void do_read_body() {}
void do_write() {}
using Strand = boost::asio::strand<tcp::socket::executor_type>;
using Timer = boost::asio::steady_timer;
tcp::socket socket_{strand_};
Strand strand_{make_strand(socket_.get_executor())};
Timer recv_deadline_{strand_};
Timer send_deadline_{strand_};
enum { max_length = 1024 };
char data_[max_length];
};
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <queue>
#include <iostream>
using boost::asio::ip::tcp;
class Server {
public:
template <typename Ex>
Server(Ex executor, uint16_t base_port) {
for (uint16_t port = base_port; port < base_port + 10; ++port) {
auto& a = acceptors_.emplace_back(executor, tcp::endpoint{{}, port});
a.listen();
accept_loop(a);
}
}
void stop() {
for (auto& a: acceptors_)
a.cancel();
}
private:
static void accept_loop(tcp::acceptor& a) {
a.async_accept(a.get_executor(), [&a](error_code ec, tcp::socket&& s) {
if (!ec) {
std::cout << "accepted " << s.remote_endpoint() << " on :" << a.local_endpoint().port() << std::endl;
std::make_shared<Session>(std::move(s))->start();
accept_loop(a);
} else {
std::cout << "exit accept_loop " << ec.message() << std::endl;
}
});
}
std::deque<tcp::acceptor> acceptors_;
};
int main() {
boost::asio::io_context context;
Server s(context.get_executor(), 7878);
context.run_for(10s);
s.stop();
context.run();
}
另请注意,现在可以取消接受循环。使用示例客户端 运行 例如
(for p in {7878..7887}; do (sleep 1.$RANDOM; nc localhost $p <<<"HELLO")& done; wait)
打印例如
accepted 127.0.0.1:37958 on :7880
accepted 127.0.0.1:45100 on :7885
accepted 127.0.0.1:42414 on :7883
accepted 127.0.0.1:49988 on :7886
accepted 127.0.0.1:44898 on :7878
accepted 127.0.0.1:43536 on :7879
accepted 127.0.0.1:35350 on :7882
accepted 127.0.0.1:40158 on :7887
accepted 127.0.0.1:53022 on :7884
accepted 127.0.0.1:39020 on :7881
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
我正在使用 boost 1.75.0 并且正在尝试更新我的服务器以便他可以同时收听两个不同的端口
假设 IP 127.0.0.1 port 6500 and port 6600.
我需要保持 Server
两个插座吗?
这是我的服务器
#include <boost/asio/io_service.hpp>
#include <boost/asio.hpp>
#include <queue>
#include "Session.h"
using boost::asio::ip::tcp;
class Server
{
public:
Server(boost::asio::io_service &io_service, short port)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
socket_(io_service)
{
do_accept();
}
private:
void do_accept(){
acceptor_.async_accept(socket_,
[this](boost::system::error_code ec) {
if (!ec) {
std::cout << "accept connection\n";
std::make_shared<Session>(std::move(socket_))->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
tcp::socket socket_;
};
这是我的会话class
#include <boost/asio/io_service.hpp>
#include <boost/asio.hpp>
#include "message.h"
#include <fstream>
#include <boost/bind/bind.hpp>
namespace {
using boost::asio::ip::tcp;
auto constexpr log_active=true;
using boost::system::error_code;
using namespace std::chrono_literals;
using namespace boost::posix_time;
};
class Session
: public std::enable_shared_from_this<Session>
{
public:
Session(tcp::socket socket)
: socket_(std::move(socket)) ,
{
}
~Session()= default;
void start();
void do_write_alive();
private:
void do_read_header();
void do_read_body();
void do_write();
using Strand = boost::asio::strand<tcp::socket::executor_type>;
using Timer = boost::asio::steady_timer;
tcp::socket socket_{strand_};
Strand strand_{make_strand(socket_.get_executor())};
Timer recv_deadline_{strand_};
Timer send_deadline_{strand_};
enum { max_length = 1024 };
char data_[max_length];
};
我没有包括 Session
class 只有构造函数的实现,因为那里不相关。
你需要两个受体。
您可以不使用 socket_ 实例,同时删除重复项。
这是一个最小的重构,运行s 10 个监听器,存储在双端队列中(为了参考稳定性):
class Server {
public:
Server(boost::asio::io_service& svc, uint16_t base_port) {
for (uint16_t port = base_port; port < base_port + 10; ++port) {
auto& a = acceptors_.emplace_back(svc, tcp::endpoint{{}, port});
a.listen();
accept_loop(a);
}
}
void stop() {
for (auto& a: acceptors_)
a.cancel();
}
private:
static void accept_loop(tcp::acceptor& a) {
a.async_accept(a.get_executor(), [&a](error_code ec, tcp::socket&& s) {
if (!ec) {
std::cout << "accepted " << s.remote_endpoint() << " on :" << a.local_endpoint().port() << std::endl;
std::make_shared<Session>(std::move(s))->start();
accept_loop(a);
} else {
std::cout << "exit accept_loop " << ec.message() << std::endl;
}
});
}
std::deque<tcp::acceptor> acceptors_;
};
使用io_context
和执行器
您可以使用执行器模型对其进行更多现代化改造:
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/bind/bind.hpp>
#include <fstream>
#include <deque>
namespace {
using boost::asio::ip::tcp;
//auto constexpr log_active = true;
using boost::system::error_code;
using namespace std::chrono_literals;
//using namespace boost::posix_time;
} // namespace
class Session : public std::enable_shared_from_this<Session> {
public:
Session(tcp::socket socket) : socket_(std::move(socket)) {}
~Session() = default;
void start() {}
void do_write_alive() {}
private:
void do_read_header() {}
void do_read_body() {}
void do_write() {}
using Strand = boost::asio::strand<tcp::socket::executor_type>;
using Timer = boost::asio::steady_timer;
tcp::socket socket_{strand_};
Strand strand_{make_strand(socket_.get_executor())};
Timer recv_deadline_{strand_};
Timer send_deadline_{strand_};
enum { max_length = 1024 };
char data_[max_length];
};
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <queue>
#include <iostream>
using boost::asio::ip::tcp;
class Server {
public:
template <typename Ex>
Server(Ex executor, uint16_t base_port) {
for (uint16_t port = base_port; port < base_port + 10; ++port) {
auto& a = acceptors_.emplace_back(executor, tcp::endpoint{{}, port});
a.listen();
accept_loop(a);
}
}
void stop() {
for (auto& a: acceptors_)
a.cancel();
}
private:
static void accept_loop(tcp::acceptor& a) {
a.async_accept(a.get_executor(), [&a](error_code ec, tcp::socket&& s) {
if (!ec) {
std::cout << "accepted " << s.remote_endpoint() << " on :" << a.local_endpoint().port() << std::endl;
std::make_shared<Session>(std::move(s))->start();
accept_loop(a);
} else {
std::cout << "exit accept_loop " << ec.message() << std::endl;
}
});
}
std::deque<tcp::acceptor> acceptors_;
};
int main() {
boost::asio::io_context context;
Server s(context.get_executor(), 7878);
context.run_for(10s);
s.stop();
context.run();
}
另请注意,现在可以取消接受循环。使用示例客户端 运行 例如
(for p in {7878..7887}; do (sleep 1.$RANDOM; nc localhost $p <<<"HELLO")& done; wait)
打印例如
accepted 127.0.0.1:37958 on :7880
accepted 127.0.0.1:45100 on :7885
accepted 127.0.0.1:42414 on :7883
accepted 127.0.0.1:49988 on :7886
accepted 127.0.0.1:44898 on :7878
accepted 127.0.0.1:43536 on :7879
accepted 127.0.0.1:35350 on :7882
accepted 127.0.0.1:40158 on :7887
accepted 127.0.0.1:53022 on :7884
accepted 127.0.0.1:39020 on :7881
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled
exit accept_loop Operation canceled