C++ 网络编程学习七

C++ 网络编程学习七

    • asio实现http服务器

asio实现http服务器

客户端实现

  1. 发送:io_context上下文
  2. server:服务器地址
  3. path:请求路径
  4. resolver_:tcp resolver,输入的不是一个域名的时候,解析出来。
  5. socket_:一个client就有一个socket_。
  6. handle_resolve:回调函数,异步处理连接。解析成功后,进行连接,连接也是异步函数handle_connect。
  7. handle_connect:处理连接,连接成功后,发送处理好的消息。发送也是异步发送,回调handle_write_request
  8. handle_write_request:等待服务器给我们发送的消息,监听对端发送的数据。当收到对方数据时,先解析响应的头部信息,接受到头部消息后,异步回调handle_read_status_line。
  9. handle_read_status_line:先读出HTTP版本,以及返回的状态码,如果状态码不是200,则返回,是200说明响应成功。接下来把所有的头部信息都读出来。回调handle_read_headers。
  10. handle_read_headers:逐行读出头部信息,然后读出响应的内容,继续监听读事件读取相应的内容,直到接收到EOF信息,也就是对方关闭,继续监听读事件是因为有可能是长连接的方式,当然如果是短链接,则服务器关闭连接后,客户端也是通过异步函数读取EOF进而结束请求。读服务器发送的数据,回调handle_read_content。
  11. handle_read_content:读取消息。
  12. main函数中:调用客户端请求服务器信息, 请求服务器的路由地址。
client(boost::asio::io_context& io_context,const std::string& server, const std::string& path): resolver_(io_context),socket_(io_context){std::ostream request_stream(&request_);request_stream << "GET " << path << " HTTP/1.0\r\n"; // 中间是有空格的request_stream << "Host: " << server << "\r\n";request_stream << "Accept: */*\r\n";request_stream << "Connection: close\r\n\r\n";size_t pos = server.find(":");std::string ip = server.substr(0, pos);std::string port = server.substr(pos + 1);// 异步解析ip和port,resolver_.async_resolve(ip, port,boost::bind(&client::handle_resolve, this,boost::asio::placeholders::error,boost::asio::placeholders::results));}void handle_resolve(const boost::system::error_code& err,const tcp::resolver::results_type& endpoints){if (!err){// 解析成功后,进行连接,连接也是boost::asio::async_connect(socket_, endpoints,boost::bind(&client::handle_connect, this,boost::asio::placeholders::error));}else{std::cout << "Error: " << err.message() << "\n";}}void handle_connect(const boost::system::error_code& err)
{if (!err){// 连接成功后,发送消息到服务器端口。boost::asio::async_write(socket_, request_,boost::bind(&client::handle_write_request, this,boost::asio::placeholders::error));}else{std::cout << "Error: " << err.message() << "\n";}
}void handle_write_request(const boost::system::error_code& err){if (!err){// boost::asio::async_read_until(socket_, response_, "\r\n",boost::bind(&client::handle_read_status_line, this,boost::asio::placeholders::error));}else{std::cout << "Error: " << err.message() << "\n";}}void handle_read_status_line(const boost::system::error_code& err){if (!err){// Check that response is OK.std::istream response_stream(&response_);std::string http_version;response_stream >> http_version;unsigned int status_code;response_stream >> status_code;std::string status_message;std::getline(response_stream, status_message);if (!response_stream || http_version.substr(0, 5) != "HTTP/"){std::cout << "Invalid response\n";return;}if (status_code != 200){std::cout << "Response returned with status code ";std::cout << status_code << "\n";return;}// Read the response headers, which are terminated by a blank line.boost::asio::async_read_until(socket_, response_, "\r\n\r\n",boost::bind(&client::handle_read_headers, this,boost::asio::placeholders::error));}else{std::cout << "Error: " << err << "\n";}}void handle_read_headers(const boost::system::error_code& err){if (!err){// Process the response headers.std::istream response_stream(&response_);std::string header;while (std::getline(response_stream, header) && header != "\r")std::cout << header << "\n";std::cout << "\n";// Write whatever content we already have to output.if (response_.size() > 0)std::cout << &response_;// Start reading remaining data until EOF.boost::asio::async_read(socket_, response_,boost::asio::transfer_at_least(1),boost::bind(&client::handle_read_content, this,boost::asio::placeholders::error));}else{std::cout << "Error: " << err << "\n";}}void handle_read_content(const boost::system::error_code& err){if (!err){// Write all of the data that has been read so far.std::cout << &response_;// Continue reading remaining data until EOF.boost::asio::async_read(socket_, response_,boost::asio::transfer_at_least(1),boost::bind(&client::handle_read_content, this,boost::asio::placeholders::error));}else if (err != boost::asio::error::eof){std::cout << "Error: " << err << "\n";}}int main(int argc, char* argv[])
{try{boost::asio::io_context io_context;client c(io_context, "127.0.0.1:8080", "/");io_context.run();getchar();}catch (std::exception& e){std::cout << "Exception: " << e.what() << "\n";}return 0;
}

服务器实现

  1. 创建服务器类对象,绑定ip和端口,以及文件路径,run起来。
  2. Sever类中,生成一个acceptor_来接收对端的连接signals_是优雅退出时绑定的一些信号所有的读写,都交给connection_manager_()来处理socket_是服务器给客户端连接分配的socketrequest_handler_处理请求
  3. resolver:解析地址和端口,返回一个端点。端点传给acceptor,acceptor绑定,监听,异步的do_accept();
  4. do_accept:异步监听连接,收到成功的连接会把请求加到connection_manager_中,request_handler_也会传入,进行连接处理。
  5. do_read:处理读取信息过程
  6. handle_request:解析资源请求的逻辑。decode路径,获取资源,检测资源是否存在。
int main(int argc, char* argv[])
{try{std::filesystem::path path = std::filesystem::current_path() / "res";// 使用 std::cout 输出拼接后的路径std::cout << "Path: " << path.string() << '\n';std::cout << "Usage: http_server <127.0.0.1> <8080> "<< path.string() <<"\n";// Initialise the server.http::server::server s("127.0.0.1", "8080", path.string());// Run the server until stopped.s.run();}catch (std::exception& e){std::cerr << "exception: " << e.what() << "\n";}return 0;
}server::server(const std::string& address, const std::string& port,const std::string& doc_root): io_service_(), // signals_(io_service_),acceptor_(io_service_), // 接收对端连接connection_manager_(),socket_(io_service_),request_handler_(doc_root){signals_.add(SIGINT);//绑定几个信号signals_.add(SIGTERM);
#if defined(SIGQUIT)signals_.add(SIGQUIT);
#endif do_await_stop(); //异步等待的方式,监听这些信号,收到信号后,连接移除,优雅关闭服务器boost::asio::ip::tcp::resolver resolver(io_service_);// 解析器,解析地址和端口,返回一个端点boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve({ address, port });acceptor_.open(endpoint.protocol());acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));acceptor_.bind(endpoint);acceptor_.listen();do_accept();
}// 异步接收。
void server::do_accept()
{acceptor_.async_accept(socket_,[this](boost::system::error_code ec){if (!acceptor_.is_open()){return;}if (!ec){// connection_manager_是连接管理类,用智能指针的方式,创建新的连接,// socket_ 给move到connection的构造函数里。// connection_manager_.start(std::make_shared<connection>(std::move(socket_), connection_manager_, request_handler_));}do_accept();});}void connection::do_read()
{auto self(shared_from_this());// 构造了一个buffer去读,bytes_transferred的意思是读到了多少数据。socket_.async_read_some(boost::asio::buffer(buffer_),[this, self](boost::system::error_code ec, std::size_t bytes_transferred){if (!ec){request_parser::result_type result;// 把返回值绑定成了一个元组。std::tie(result, std::ignore) = request_parser_.parse(request_, buffer_.data(), buffer_.data() + bytes_transferred);// 如果返回值是good,就继续处理请求if (result == request_parser::good){request_handler_.handle_request(request_, reply_);do_write();}// 如果是bad,请求直接返回掉,返回值写到回调里。else if (result == request_parser::bad){reply_ = reply::stock_reply(reply::bad_request);do_write();}else{ //还没解析完do_read();}}else if (ec != boost::asio::error::operation_aborted){connection_manager_.stop(shared_from_this());}});
}void request_handler::handle_request(const request& req, reply& rep)
{// 解码,如果是get请求,后面可能会带一些参数// decode路径std::string request_path;if (!url_decode(req.uri, request_path)){rep = reply::stock_reply(reply::bad_request);return;}// 如果是空,返回一个bad_requestif (request_path.empty() || request_path[0] != '/'|| request_path.find("..") != std::string::npos){rep = reply::stock_reply(reply::bad_request);return;}// 只发送一个斜杠,返回index.htmlif (request_path[request_path.size() - 1] == '/'){request_path += "index.html";}// 区分目录还是文件std::size_t last_slash_pos = request_path.find_last_of("/");std::size_t last_dot_pos = request_path.find_last_of(".");std::string extension;if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos){extension = request_path.substr(last_dot_pos + 1);}// 打开文件std::string full_path = doc_root_ + request_path;std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary);if (!is){rep = reply::stock_reply(reply::not_found);return;}// Fill out the reply to be sent to the client.rep.status = reply::ok;char buf[512];// 先把头部添上,再返回给对端while (is.read(buf, sizeof(buf)).gcount() > 0)rep.content.append(buf, is.gcount());rep.headers.resize(2);rep.headers[0].name = "Content-Length";rep.headers[0].value = std::to_string(rep.content.size());rep.headers[1].name = "Content-Type";rep.headers[1].value = mime_types::extension_to_type(extension);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/759125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

海外云手机如何帮助亚马逊引流?

随着全球化的推进&#xff0c;出海企业和B2B外贸企业越来越注重海外市场的开拓&#xff0c;这已成为企业争夺市场份额的重要策略。本文将重点探讨海外云手机在优化亚马逊店铺引流方面的作用和优势。 海外云手机是一种在云端运行的虚拟手机&#xff0c;能够在单一芯片上多开几个…

python爬虫基础实验:通过DBLP数据库获取数据挖掘顶会KDD在2023年的论文收录和相关作者信息

Task1 读取网站主页整个页面的 html 内容并解码为文本串&#xff08;可使用urllib.request的相应方法&#xff09;&#xff0c;将其以UTF-8编码格式写入page.txt文件。 Code1 import urllib.requestwith urllib.request.urlopen(https://dblp.dagstuhl.de/db/conf/kdd/kdd202…

PyTorch 深度学习(GPT 重译)(二)

四、使用张量表示真实世界数据 本章内容包括 将现实世界的数据表示为 PyTorch 张量 处理各种数据类型 从文件加载数据 将数据转换为张量 塑造张量&#xff0c;使其可以作为神经网络模型的输入 在上一章中&#xff0c;我们了解到张量是 PyTorch 中数据的构建块。神经网络…

Excel使用VLOOKUP函数

VLOOKUP(lookup_value,table_array,col_index_num,range_lookup) 释义&#xff1a; lookup_value&#xff1a;要查找的值&#xff0c;包括数字&#xff0c;文本等 table_array&#xff1a;要查找的值以及预期返回的内容所在的区域 col_index_num&#xff1a;查找的区域的列…

微信小程序订阅消息(一次性订阅消息)

1、准备工作 登录微信公众平台–>订阅消息–>在公共模板库中选中一个模版–>将模版id复制&#xff0c;前后端都需要。 点击详情–>查看详细内容模版 复制给后端 2、相关api的使用 前端使用&#xff1a;wx.requestSubscribeMessage wx.openSetting wx.getSetti…

Gateway新一代网关

Gateway新一代网关 1、概述 ​ Cloud全家桶中有个很重要的组件就是网关&#xff0c;在1.x版本中都是采用的Zuul网关&#xff1b; ​ 但在2.x版本中&#xff0c;zuul的升级一直跳票&#xff0c;SpringCloud最后自己研发了一个网关SpringCloud Gateway替代Zuul。 ​ 官网&…

Rust构建高性能爬虫程序

一、概述 大数据时代得开启&#xff0c;数据分析的重要性日益增加&#xff0c;网页爬虫在信息收集、数据分析等领域发挥着重要作用。Rust&#xff0c;以其卓越的性能和内存安全性著称&#xff0c;非常适合构建高性能和高效率的爬虫程序。本文将详细介绍如何使用 Rust 构建高性…

ubuntu部署wireguard服务端,ubuntu部署wireguard客户端

docker部署方式 docker run -d \--namewg-easy \-e WG_HOST6.6.6.6服务端IP \-e PASSWORD123abc登陆管理密码 \-e WG_DEFAULT_ADDRESS10.0.8.x客户端 IP 地址范围 \-e WG_DEFAULT_DNS1.1.1.1配置dns \-e WG_ALLOWED_IPS10.0.8.0/24 \-e WG_PERSISTENT_KEEPALIVE25 \-v ~/.wg-e…

uniapp、vue2.6、H5,利用腾讯TRTC,快速跑通1v1视频功能

多人视频聊天室搭建&#xff0c;官网已有相关demo和案例&#xff0c;需要快速搭建多人聊天室直接进入以下网站&#xff1a; 实时音视频 Web & H5 (Vue2/Vue3)-视频通话&#xff08;含 UI&#xff09;-文档中心-腾讯云说明&#xff1a;https://cloud.tencent.com/document/…

24计算机考研调剂 | 温州大学

温州大学招收有计算机基础调剂生 考研调剂招生信息 各位2024年考研同学你们好&#xff1a;温州大学化学与材料工程学院 丁益宏 课题组招收学生 【招收专业】 学硕&#xff1a;化学、材料科学与工程 专硕&#xff1a;资源与环境&#xff08;环境新材料方向&#xff09;、材料化…

北斗短报文+4G应急广播系统:全面预警灾害信息 构建安全美好乡村

建设社会主义新农村是确保小康社会宏伟目标如期实现的必然要求&#xff0c;是构建和谐社会的重要内容。针对现代农业发展的要求&#xff0c;通过完善专业化监测预报技术&#xff0c;提高精细化的灾害监测预警能力&#xff0c;建设广覆盖的预警信息发布网络&#xff0c;建设有效…

Mybatis查询列表中的坑

前言 从一个Bug入手&#xff0c;看一个或许被很多人忽略的Mybatis使用中的大坑。 中间是排查思路。如果不想看排查过程&#xff0c;可以直接从[真正的解决方案]开始看。 Bug描述 JavaWeb项目中&#xff0c;使用Mybatis查询pg数据库。 在查询一个列表数据的时候&#xff0c;发…

dataGridView 绑定List 显示内容不刷新

绑定后,原list值变动,显示内容会刷新 绑定后,list新添加的值时不会显示到界面,需要重新绑定list 微软的Bug 参考代码 public class Student{public string Name { get; set; }}List<Student> list new List<Student>();private void Form2_Load(object sender,…

练习 9 Web [SUCTF 2019]CheckIn (未拿到flag)

上传图片格式的木马文件&#xff1a; 返回 <? in contents!,存在PHP代码检测 上传非图片格式文件&#xff1a; 返回 不允许非image 修改木马PHP代码规避检测 <? ?> 改为 < script language“php”>< /script ><?php eval($_POST[shell]);?>…

JAVA实现压力测试

在Java中实现压力测试通常涉及到使用多线程来模拟并发操作。以下是一个简单的例子&#xff0c;使用Java的ExecutorService和Callable来执行并发的任务&#xff0c;进行简单的压力测试。 package useful; import java.time.LocalDateTime; import java.util.Calendar; import j…

PyTorch 深度学习(GPT 重译)(四)

第二部分&#xff1a;从现实世界的图像中学习&#xff1a;肺癌的早期检测 第 2 部分的结构与第 1 部分不同&#xff1b;它几乎是一本书中的一本书。我们将以几章的篇幅深入探讨一个单一用例&#xff0c;从第 1 部分学到的基本构建模块开始&#xff0c;构建一个比我们迄今为止看…

C#关键字 sealed、unsafe、virtual、volatile

sealed 应用于某个类时&#xff0c;sealed 修饰符可阻止其他类继承自该类。 在下面的示例中&#xff0c;类 B 继承自类 A&#xff0c;但没有类可以继承自类 B。 class A {} sealed class B : A {}还可以对替代基类中的 虚方法 或 属性的方法 或 属性 使用 sealed 修饰符。 这…

酷炫的粒子动态表白HTML源码

源码介绍 酷炫的粒子动态表白HTML源码&#xff0c;自己自定义文字&#xff0c;动态组合文字&#xff0c;进行表白&#xff0c;喜欢的朋友可以下载使用&#xff0c;很不错的表白HTML代码 下载地址 酷炫的粒子动态表白HTML源码

2024蓝桥杯每日一题(Flood Fill)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;扫雷 试题二&#xff1a;动态网络 试题三&#xff1a;走迷宫 试题四&#xff1a;画图 试题一&#xff1a;扫雷 【题目描述】 扫雷是一种计算机游戏&#xff0c;在 2020 世纪 8080 年代…

【论文阅读】通过组件对齐评估和改进 text-to-SQL 的组合泛化

Measuring and Improving Compositional Generalization in Text-to-SQL via Component Alignment NAACL 2022| CCF B Abstract 在 text-to-SQL 任务中&#xff0c;正如在许多 NLP 中一样&#xff0c;组合泛化是一个重大挑战&#xff1a;神经网络在训练和测试分布不同的情况…