c++ - Boost ASIO 网络服务器/客户端
Posted
技术标签:
【中文标题】c++ - Boost ASIO 网络服务器/客户端【英文标题】:c++ - Boost ASIO networking server/client 【发布时间】:2017-01-04 23:14:54 【问题描述】:我为客户端和服务器编写了一个程序。该程序当前执行以下操作:
-
服务器侦听连接的端点
客户端连接到服务器
服务器在接受连接时发送消息
客户端收到消息
我正在异步执行此操作。但是,问题是他们只能发送/接收一条消息。之后,他们就终止了。以下是我的代码:
#include <iostream>
#include <vector>
#include<boost/asio.hpp>
std::vector<char> buff(256);
void SendHandler(boost::system::error_code ex)
std::cout << " do something here" << std::endl;
void ReadHandler(boost::system::error_code ex)
std::cout << " print the buffer data..." << std::endl;
std::cout << buff.data() << std::endl;
void Server()
boost::asio::io_service service;
using namespace boost::asio::ip;
tcp::endpoint endpoint(tcp::v4(), 4000);
tcp::acceptor acceptor(service, endpoint);
tcp::socket socket(service);
std::cout << "[Server] Waiting for connection" << std::endl;
acceptor.accept(socket);
std::cout << "[Server] Accepted a connection from client" << std::endl;
std::string msg = "Message from server";
socket.async_send(boost::asio::buffer(msg), SendHandler);
service.run();
void Client()
boost::asio::io_service service;
using namespace boost::asio::ip;
tcp::endpoint endpoint(address::from_string("127.0.0.1"), 4000);
tcp::socket socket(service);
std::cout << "[Client] Connecting to server..." << std::endl;
socket.connect(endpoint);
std::cout << "[Client] Connection successful" << std::endl;
socket.async_read_some(boost::asio::buffer(buff), ReadHandler);
service.run();
int main(int argc, char **argv)
if(argc == 1)
std::cout << "Please specify s for server or c for client" << std::endl;
return -1;
if(argv[1][0] == 's')
Server();
else
Client();
return 0;
我想扩展这个程序,以便:
-
服务器可以监听,客户端可以无限期地发送请求。更像是一种单向聊天系统。
服务器能够连接到多个客户端。
将async_send()
和service.run()
置于无限循环中并没有帮助。它只是在客户端一遍又一遍地打印消息,直到客户端终止。
我对@987654324@ 甚至对network programming
还是很陌生。请告诉我应该在我的代码中修改的位置和内容?
【问题讨论】:
【参考方案1】:从学习一些基础知识开始。该库提供了出色的教程和示例,将引导您了解同步和异步服务器的概念和示例。
http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio.html
从头开始。使用计时器和回调完成基本概念。继续本教程进入网络。在几个小时的过程中,通过编辑教程程序来构建核心想法,以自己尝试想法。
然后继续阅读示例部分。 “聊天”示例非常接近您要构建的内容。此特定示例显示如何通过在读取处理程序中重新发出 async_reads 来打开连接。只要服务线程继续使用分配的 async_accept 任务运行,异步 asio 服务器就会为多个客户端提供服务。
http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/examples/cpp11_examples.html http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/example/cpp11/chat/chat_server.cpp
【讨论】:
【参考方案2】:实现一个异步 TCP 服务器
异步 TCP 服务器是满足以下条件的分布式应用程序的一部分:
在客户端-服务器通信模型中充当服务器 通过 TCP 协议与客户端应用程序通信 使用异步 I/O 和控制操作 可以同时处理多个客户端典型的异步 TCP 服务器按照以下算法工作:
分配一个接受器套接字并将其绑定到特定的 TCP 端口。 启动异步接受操作。 产生一个或多个控制线程并将它们添加到运行 Boost.Asio 事件循环的线程池中。 当异步接受操作完成后,发起一个新的接受下一个连接请求。 启动异步读取操作,读取已连接客户端的请求。 异步读取操作完成后,处理请求并准备响应消息。 发起异步写入操作,向客户端发送响应消息。 当异步写入操作完成后,关闭连接并释放套接字。//responsible for handling a single client by reading the request message, processing it, and then sending back the response message.
//Each instance of the Service class is intended to handle one connected client
//by reading the request message, processing it, and then sending the response message back.
class Service
public:
//The class's constructor accepts a shared pointer to an object representing a socket connected to a particular client as an argument
// and caches this pointer. This socket will be used later to communicate with the client application.
Service(std::shared_ptr<asio::ip::tcp::socket> sock) : m_sock(sock)
//This method starts handling the client by initiating the asynchronous reading operation
//to read the request message from the client specifying the onRequestReceived() method as a callback.
void StartHandling()
private:
void onRequestReceived(const boost::system::error_code &ec,
std::size_t bytes_transferred)
void onResponseSent(const boost::system::error_code &ec,
std::size_t bytes_transferred)
// Here we perform the cleanup.
void onFinish()
delete this;
//To keep things simple, we implement a dummy service which only emulates the execution of certain operations
//The request processing emulation consists of performing many increment operations to emulate operations
//that intensively consume CPU and then putting the thread of control to sleep for some time to emulate I/O operations
std::string ProcessRequest(asio::streambuf &request)
private:
std::shared_ptr<asio::ip::tcp::socket> m_sock;
std::string m_response;
asio::streambuf m_request;
;
//responsible for accepting the connection requests arriving from clients and instantiating the objects of the Service class,
// which will provide the service to connected clients.
class Acceptor
public:
//Its constructor accepts a port number on which it will listen for the incoming connection requests as its input argument.
Acceptor(asio::io_service &ios, unsigned short port_num) : m_ios(ios),
//The object of this class contains an instance of the asio::ip::tcp::acceptor class as its member named m_acceptor,
//which is constructed in the Acceptor class's constructor.
m_acceptor(m_ios,
asio::ip::tcp::endpoint(
asio::ip::address_v4::any(),
port_num)),
m_isStopped(false)
//The Start() method is intended to instruct an object of the Acceptor class to start listening and accepting incoming connection requests.
void Start()
// Stop accepting incoming connection requests.
void Stop()
private:
void InitAccept()
void onAccept(const boost::system::error_code &ec,
std::shared_ptr<asio::ip::tcp::socket> sock)
private:
asio::io_service &m_ios;
//used to asynchronously accept the incoming connection requests.
asio::ip::tcp::acceptor m_acceptor;
std::atomic<bool> m_isStopped;
;
//represents the server itself
class Server
public:
Server()
// Start the server.
// Accepts a protocol port number on which the server should listen for the incoming connection requests
// and the number of threads to add to the pool as input arguments and starts the server
// Nonblocking Method
void Start(unsigned short port_num,
unsigned int thread_pool_size)
// Stop the server.
// Blocks the caller thread until the server is stopped and all the threads running the event loop exit.
void Stop()
private:
asio::io_service m_ios;
std::unique_ptr<asio::io_service::work> m_work;
std::unique_ptr<Acceptor> acc;
std::vector<std::unique_ptr<std::thread>> m_thread_pool;
;
int main()
unsigned short port_num = 3333;
try
//it instantiates an object of the Server class named srv.
Server srv;
//before starting the server, the optimal size of the pool is calculated.
// The general formula often used in parallel applications to find the optimal number of threads is the number of processors the computer has multiplied by 2.
// We use the std::thread::hardware_concurrency() static method to obtain the number of processors.
unsigned int thread_pool_size =
std::thread::hardware_concurrency() * 2;
//because this method may fail to do its job returning 0,
// we fall back to default value represented by the constant DEFAULT_THREAD_POOL_SIZE, which is equal to 2 in our case.
if (thread_pool_size == 0)
thread_pool_size = DEFAULT_THREAD_POOL_SIZE;
srv.Start(port_num, thread_pool_size);
std::this_thread::sleep_for(std::chrono::seconds(60));
srv.Stop();
catch (system::system_error &e)
std::cout << "Error occured! Error code = "
<< e.code() << ". Message: "
<< e.what();
return 0;
实现一个异步 TCP 客户端
支持异步执行请求和请求取消功能的异步 TCP 客户端应用程序:
来自用户的输入应在单独的线程(用户界面线程)中处理。此线程不应被阻塞很长时间。 用户应该能够向不同的服务器发出多个请求。 用户应该能够在之前发出的请求完成之前发出新的请求。 用户应该能够在之前发出的请求完成之前取消它们。// Function pointer type that points to the callback
// function which is called when a request is complete.
// Based on the values of the parameters passed to it, it outputs information about the finished request.
typedef void (*Callback)(unsigned int request_id, // unique identifier of the request is assigned to the request when it was initiated.
const std::string &response, // the response data
const system::error_code &ec); // error information
// data structure whose purpose is to keep the data related to a particular request while it is being executed
struct Session
Session(asio::io_service &ios,
const std::string &raw_ip_address,
unsigned short port_num,
const std::string &request,
unsigned int id,
Callback callback) : m_sock(ios),
m_ep(asio::ip::address::from_string(raw_ip_address),
port_num),
m_request(request),
m_id(id),
m_callback(callback),
m_was_cancelled(false)
asio::ip::tcp::socket m_sock; // Socket used for communication
asio::ip::tcp::endpoint m_ep; // Remote endpoint.
std::string m_request; // Request string.
// streambuf where the response will be stored.
asio::streambuf m_response_buf;
std::string m_response; // Response represented as a string.
// Contains the description of an error if one occurs during
// the request lifecycle.
system::error_code m_ec;
unsigned int m_id; // Unique ID assigned to the request.
// Pointer to the function to be called when the request
// completes.
Callback m_callback;
bool m_was_cancelled;
std::mutex m_cancel_guard;
;
// class that provides the asynchronous communication functionality.
class AsyncTCPClient : public boost::noncopyable
public:
AsyncTCPClient(unsigned char num_of_threads)
// initiates a request to the server
void emulateLongComputationOp(
unsigned int duration_sec, //represents the request parameter according to the application layer protocol
const std::string &raw_ip_address, //specify the server to which the request should be sent.
unsigned short port_num, //specify the server to which the request should be sent.
Callback callback, //callback function, which will be called when the request is complete.
unsigned int request_id) // unique identifier of the request
// cancels the previously initiated request designated by the request_id argument
void cancelRequest(unsigned int request_id) //accepts an identifier of the request to be canceled as an argument.
// blocks the calling thread until all the currently running requests complete and deinitializes the client.
void close()
private:
// method is called whenever the request completes with any result.
void onRequestComplete(std::shared_ptr<Session> session)
private:
asio::io_service m_ios;
std::map<int, std::shared_ptr<Session>> m_active_sessions;
std::mutex m_active_sessions_guard;
std::unique_ptr<boost::asio::io_service::work> m_work;
std::list<std::unique_ptr<std::thread>> m_threads;
;
// a function that will serve as a callback, which we'll pass to the AsyncTCPClient::emulateLongComputationOp() method
// It outputs the result of the request execution and the response message to the standard output stream if the request is completed successfully
void handler(unsigned int request_id,
const std::string &response,
const system::error_code &ec)
int main()
try
AsyncTCPClient client(4);
// Here we emulate the user's behavior.
// creates an instance of the AsyncTCPClient class and then calls its emulateLongComputationOp() method to initiate three asynchronous requests
// User initiates a request with id 1.
client.emulateLongComputationOp(10, "127.0.0.1", 3333, handler, 1);
// Decides to exit the application.
client.close();
catch (system::system_error &e)
std::cout << "Error occured! Error code = " << e.code()
<< ". Message: " << e.what();
return e.code().value();
return 0;
;
设置环境
1.安装 CMake
cd ~
wget https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5.tar.gz
tar xf cmake-3.14.5.tar.gz
cd cmake-3.14.5
./bootstrap --parallel=10
make -j4
sudo make -j4 install
2。安装 Boost
cd ~
wget https://boostorg.jfrog.io/artifactory/main/release/1.69.0/source/boost_1_69_0.tar.gz
tar xf boost_1_69_0.tar.gz
cd boost_1_69_0
./bootstrap.sh
./b2 ... cxxflags="-std=c++0x -stdlib=libc++" linkflags="-stdlib=libc++" ...
sudo ./b2 toolset=gcc -j4 install
如何构建
mkdir build
cd build
cmake ..
cmake --build .
如何运行
运行服务器
./bin/server
我们可以检查服务器是否运行
netstat -tulpn | grep LISTEN
tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:3333 0.0.0.0:* LISTEN 6866/./bin/server <===============
tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:5433 0.0.0.0:* LISTEN -
tcp6 0 0 :::445 :::* LISTEN -
tcp6 0 0 :::5000 :::* LISTEN -
tcp6 0 0 :::5001 :::* LISTEN -
tcp6 0 0 :::139 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:631 :::* LISTEN -
运行客户端
./bin/client
Request #1 has completed. Response: Response from server
您可以在Boost Asio C++ Network Programming Client Server找到该项目
【讨论】:
以上是关于c++ - Boost ASIO 网络服务器/客户端的主要内容,如果未能解决你的问题,请参考以下文章
使用 boost-asio 的 C++ 和 Python 程序之间的客户端服务器