1.引用 和复制(不用&做参数) 的区别
(1)第一个:肯定是一个原参数操作,另外一个是对原参数 复制一个副本 去操作(开销问题)
(2)第二个:如果是公共参数,比如io_context,他始终只有一个(与内核相关),只能由&
简介
本文基于c++,重点是来掌握c++的异步概念.也是基于boost的asio库
服务端
对话设计
因为是io复用的服务器设计,我们的服务器只有一个端口和ip地址,只就要产生多个 多个会话区
即是 客户端
以防内存泄漏,本设计采用智能指针来控制对象的释放.
参考资料
using namespace boost::asio::ip;class session:public std::enable_shared_from_this<session> {
public:
session(boost::asio::io_context &io_context):socket_(io_context){};
void start() {auto self(shared_from_this());boost::asio::async_read_until(socket_,buffer,'\n',[self](boost::system::error_code ec,std::size_t len) {if(!ec) {std::istream is(&self->buffer);std::string line;std::getline(is,line);std::cout<<"Received: "<<line<<std::endl;boost::asio::async_write(self->socket_,boost::asio::buffer("Receive is finished"),[self](boost::system::error_code ec) {if(!ec) {self->start();}});}elsestd::cout<<ec.failed()<<std::endl;});
}
private:tcp::socket socket_;boost::asio::streambuf buffer;
};
这个采用递归一直读写
boost::asio::async_read_until(socket, buffer, delimiter, read_handler);
- socket:
类型:boost::asio::basic_stream_socket 或其他支持异步读取的套接字类型。
作用:指定从哪个套接字读取数据。- buffer:
类型:boost::asio::streambuf 或其他动态缓冲区类型。
作用:存储读取到的数据。async_read_until 会将读取到的数据存储到这个缓冲区中。- delimiter:
类型:char 或 std::string。
作用:指定读取操作的结束条件。当读取到的数据中包含这个分隔符时,读取操作将停止。例如,如果你指定分隔符为 \n,则读取操作会在遇到换行符时停止。- read_handler:
类型:回调函数或 lambda 表达式。
作用:在读取操作完成时被调用。回调函数的签名通常为:void read_handler(const boost::system::error_code& ec, std::size_t bytes_transferred);
boost::asio::async_write(socket, buffers, write_handler);
- socket:
类型:boost::asio::basic_stream_socket 或其他支持异步写入的流类型。
作用:指定将数据写入到哪个套接字或流中。- buffers:
类型:boost::asio::const_buffer 或 std::vectorboost::asio::const_buffer。
作用:指定要写入的数据。const_buffer 是一个表示常量缓冲区的类,可以包含指向数据的指针和数据的大小。你可以使用 - - - —boost::asio::buffer 函数来创建 const_buffer 对象。- write_handler:
类型:回调函数或 lambda 表达式。
作用:在写入操作完成时被调用。回调函数的签名通常为:
服务端
class server {
public:server(boost::asio::io_context &io_context,short port):acceptor_(io_context,tcp::endpoint(tcp::v4(),port)),io_context_(io_context) {std::cout<<"Server is running on port: "<<port<<std::endl;start_accept();}void start_accept() {auto new_session=std::make_shared<session>(io_context_);acceptor_.async_accept(new_session->socket(),[this,new_session](boost::system::error_code ec) {if(!ec) {new_session->start();}start_accept();//采用递归来不断连接});}
private:boost::asio::io_context &io_context_;tcp::acceptor acceptor_;
};
acceptor_.async_accept
参数为 socket:
类型:boost::asio::basic_stream_socket 或其他支持异步写入的流类型。(其实是客户端的socekt)
回调函数
io_context
为服务器的socket
运行
int main() {try {boost::asio::io_context io_context;server s(io_context,8080);std::vector<std::thread>threads(5);for(int i=0;i<threads.size();i++) {threads[i]=std::thread([&io_context]() {io_context.run();});}for(auto &thread: threads) {thread.join();}} catch (std::exception ec) {std::cout<<ec.what()<<std::endl;}
}
使用了多个进程来运行io_context.run();
客户端
tcp::resolver
在 Boost.Asio 中,boost::asio::ip::tcp::resolver 是一个用于解析主机名和端口名称的类。它将主机名和端口名称转换为一个或多个 tcp::endpoint 对象,这些对象表示可以连接到的网络地址和端口。
tcp::resolver 的作用
tcp::resolver 的主要作用是将主机名和端口名称解析为一个或多个 tcp::endpoint 对象。这个过程通常涉及以下步骤:
- DNS 查询:将主机名解析为一个或多个 IP 地址。
- 端口解析:将端口名称解析为一个端口号。
- 生成 tcp::endpoint:将解析得到的 IP 地址和端口号组合成一个或多个 tcp::endpoint 对象。
方法
tcp::resolver::query()
query(const std::string& host, const std::string& service);
void async_resolve(const query& q,ResolveHandler handler);
q:一个 tcp::resolver::query 对象,包含主机名和端口名称。
handler:解析完成后的回调函数。回调函数的签名通常为:void handler(const boost::system::error_code& ec, tcp::resolver::results_type endpoints);
返回一个或多个endpoint对象
boost::asio::async_connect(socket_, endpoints, [this, self](boost::system::error_code ec, tcp::endpoint)
- 使用 async_connect 异步连接到解析得到的 tcp::endpoint。
#include <iostream>
#include <boost/asio.hpp>
#include <boost/enable_shared_from_this.hpp>using boost::asio::ip::tcp;class client : public std::enable_shared_from_this<client>
{
public:client(boost::asio::io_context& io_context): socket_(io_context), resolver_(io_context){}void start(const std::string& server, const std::string& port){auto self(shared_from_this());tcp::resolver::query query(server, port);resolver_.async_resolve(query,[this, self](boost::system::error_code ec, tcp::resolver::results_type endpoints){if (!ec){boost::asio::async_connect(socket_, endpoints,[this, self](boost::system::error_code ec, tcp::endpoint){if (!ec){do_write();}else{std::cerr << "Connection failed: " << ec.message() << std::endl;}});}else{std::cerr << "Resolve failed: " << ec.message() << std::endl;}});}private:void do_write(){auto self(shared_from_this());std::string message = "Hello, server!\n";boost::asio::async_write(socket_, boost::asio::buffer(message),[this, self](boost::system::error_code ec, std::size_t /*length*/){if (!ec){// 继续读取数据do_read();}else{std::cerr << "Write failed: " << ec.message() << std::endl;}});}void do_read(){auto self(shared_from_this());boost::asio::async_read_until(socket_, buffer_, '\n',[this, self](boost::system::error_code ec, std::size_t length){if (!ec){std::istream is(&buffer_);std::string line;std::getline(is, line);std::cout << "Received from server: " << line << std::endl;// 清空缓冲区buffer_.consume(length);// 继续读取数据do_read();}else{std::cerr << "Read failed: " << ec.message() << std::endl;}});}tcp::socket socket_;tcp::resolver resolver_;boost::asio::streambuf buffer_;
};int main()
{try{boost::asio::io_context io_context;auto c = std::make_shared<client>(io_context);c->start("127.0.0.1", "8080");io_context.run();}catch (std::exception& e){std::cerr << "Exception: " << e.what() << std::endl;}return 0;
}