简易版“异步多线程服务器”

news/2025/4/2 7:18:09/

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;
}

http://www.ppmy.cn/news/1584579.html

相关文章

python 语法篇(一)

目录 1 正则匹配注意点11.1 正则匹配字符串写法1.2 创建re函数&#xff08;1&#xff09;re.search()--搜索第一个匹配项&#xff08;2&#xff09;re.match() - 从字符串开头匹配&#xff08;3&#xff09;re.findall() - 返回所有匹配项的列表&#xff08;4&#xff09;re.fi…

JAVA实现动态IP黑名单过滤

一些恶意用户(可能是黑客、爬虫、DDoS 攻击者)可能频繁请求服务器资源&#xff0c;导致资源占用过高。因此需要一定的手段实时阻止可疑或恶意的用户&#xff0c;减少攻击风险。 通过 IP 封禁&#xff0c;可以有效拉黑攻击者&#xff0c;防止资源被滥用&#xff0c;保障合法用户…

实战 | 基于 SpringBoot + UniApp 打造国际版打车系统:架构设计与性能优化全解析

✅ 一、引言&#xff1a;国际版打车系统的技术挑战 随着共享出行在全球范围内的快速发展&#xff0c;跨国打车平台如 Uber、Lyft 和 DiDi 等纷纷崛起。开发一套国际版打车系统&#xff0c;不仅要满足国内需求&#xff0c;还需要应对以下技术挑战&#xff1a; &#x1f30d; 多…

Altium Designer 24 PCB编辑器[设计]栏找不到[规则]选项而只有[Constraints Manager]选项

Altium Designer 24 PCB编辑器[设计]栏找不到[规则]选项而只有[Constraints Manager]选项 问题描述问题原因解决方法 问题描述 在使用 Altium Designer 24 的PCB编辑器时&#xff0c;发现有的PCB文件的【设计】栏下有【规则】这个选项&#xff0c;有的PCB文件的【设计】栏下没…

蓝桥杯 之 LCA算法

文章目录 习题1483.树节点的第K个祖先拓展&#xff1a;LCA LCA问题&#xff0c;就是最近公共祖先的问题 习题 1483.树节点的第K个祖先 1483.树节点的第K个祖先 普通的做法&#xff0c;当然是一个个往上面搜索&#xff0c;但是这样的话时间复杂度是o(k),那么能不能每次求解的是…

JVM如何判断一个对象可以被回收

在 Java 中&#xff0c;JVM 使用 垃圾回收器 (GC) 来自动管理内存。JVM 判断一个对象是否可以被回收的主要依据是 对象是否可达。具体来说&#xff0c;如果某个对象不再被任何可达的引用所引用&#xff0c;那么这个对象就可以被认为是 垃圾&#xff0c;可以被回收。 判断一个对…

win 远程 ubuntu 服务器 安装图形界面

远程结果&#xff1a;无法使用docker环境使用此方法 注意要写IP和:数字 在 ubuntu 服务器上安装如下&#xff1a; # 安装 sudo apt-get install tightvncserver # 卸载 sudo apt purge tightvncserver sudo apt autoremove#安装缺失的字体包&#xff1a; sudo apt update s…

【自学笔记】PHP语言基础知识点总览-持续更新

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1. PHP 简介2. PHP 环境搭建3. 基本语法变量与常量数据类型运算符 4. 控制结构条件语句循环语句 5. 函数函数定义与调用作用域 6. 数组7. 字符串8. 表单处理9. 会话…