计算机网络(4) --- 协议定制
计算机网络(3) --- 网络套接字TCP_哈里沃克的博客-CSDN博客
https://blog.csdn.net/m0_63488627/article/details/132035757?spm=1001.2014.3001.5501
目录
1. 协议的基础知识
TCP协议通讯流程
编辑
2.协议
1.介绍
2.手写协议
1.内容
2.接口
3.序列化和反序列化
4.协议化
5.读操作
3.客户端和服务端的业务逻辑
1.服务端
2.客户端
1. 协议的基础知识
TCP协议通讯流程
1.不论是三次握手四次挥手还是数据的传输,其实都是操作系统进行执行的。那么两边的函数也只是操作系统的调用接口,操作系统依然是整体的执行者
2.那么我们不能简单的认为accept就是构建链接,因为链接的建立是操作系统提供的,accept更多的是以一种接收管理的姿态。那么三次握手有没有aceept其实不大有关系。
3.链接其实是一种结构体,该结构体是用于存储客户端连接服务器时对客户端的描述,毕竟连接服务端的不一定只有一个客户端,只要客户端多起来,就一定需要被管理,那么aceept的作用就是将接收到的链接进行描述管理
2.协议
1.介绍
1.协议是一种 "约定"。 socket api的接口,之前写的套接字在读写数据时, 都是按 "字节流" 的方式来发送接收的。
2.但是我们需要传输一些"结构化的数据",比如图片,视频之类的东西。设计为了这些功能的实现,我们将这些东西对应的字节流组成一个结构体,那么由该结构体存储,只要我们将这些字节流存储到结构体内,随后进行序列化得到一个字节流,之后传入到网络中去。接收方接收,得到的则是一个字节流,反序列化出结构体再将所有的数据拿出来,这样就实现了所有形式的数据都能被一个报文直接转发过来。
3.同时也要保证接收方收到一个完整的报文。udp不需要考虑,因为它面向数据报的;tcp不同,它是传输字节流的,需要考虑。
2.手写协议
1.内容
1.为了保证接收方收到一个完整的报文,我们需要自己设计报文和报文之间的边界。
2.除了物理层都没有返送和接收的直接连接,应用层的数据想要发送,其实这些数据都在应用层的缓冲区中,而发送的过程,其实是像tcp/ip层进行拷贝,把应用层的缓冲区拷贝到tcp/ip层的发送缓冲区,而另一边的主机则是通过tcp/ip层的接收缓冲区拷贝下层传上来的数据。这些数据最终是通过网络发送的。应用层的函数调用write和read接口都是拷贝函数。那考虑最终结果其实呈现出的是:C的发送缓冲区的数据拷贝到S的接收缓冲区,反之亦然。
3.由于两边都拥有发送和接收缓冲区,那么也就意味着两边同时的传输是不影响的,这种工作模式是全双工的
4.发送数据很多,并且对端不处理这些发送过来的数据,难免出现数据扎堆出现在缓冲区中,那么读取这些数据就想要分离出以一个报文为单位的数据。这种划分有三种方法:定长,定特殊符号或者这自描述方法
2.接口
与read的作用一致,都是把字节流发送出去
与write的作用一致,都是把字节流接收会来
3.序列化和反序列化
#define SEP " " #define SEP_LEN strlen(SEP) // 不要使用sizeof #define LINE_SEP "\r\n" #define LINE_SEP_LEN strlen(LINE_SEP) // 不要使用sizeofclass Request { public:Request(){}Request(int x_, int y_, char op_): x(x_), y(y_), op(op_){}bool serialize(std::string *out){*out = "";std::string x_string = std::to_string(x);std::string y_string = std::to_string(y);*out = x_string;*out += SEP;*out += op;*out += SEP;*out += y_string;*out += LINE_SEP;}bool deserialize(const std::string &in){auto left = in.find(SEP);auto right = in.find(SEP);if (left == std::string::npos || right == std::string::npos)return false;if (left == right)return false;if (right - (left + SEP_LEN))return false;std::string x_string = in.substr(0, left);if (x_string.empty())return false;std::string y_string = in.substr(right + SEP_LEN);if (y_string.empty())return false;x = std::stoi(x_string);y = std::stoi(y_string);op = in[left + SEP_LEN];return true;}public:int x;int y;char op; };class Response { public:Response(){}Response(int exitcode_, int result_): exitcode(exitcode_), result(result_){}bool serialize(std::string *out){*out = "";std::string ec_string = std::to_string(exitcode);std::string res_string = std::to_string(result);*out = ec_string;*out += SEP;*out += res_string;*out += LINE_SEP;return true;}bool deserialize(const std::string &in){auto mid = in.find(SEP);if (mid == std::string::npos)return false;std::string ec_string = in.substr(0, mid);std::string res_string = in.substr(mid + SEP_LEN);if (ec_string.empty() || res_string.empty())return false;exitcode = std::stoi(ec_string);result = std::stoi(res_string);return true;}public:int exitcode;int result; };基于计算的业务处理逻辑下:
1.request表示请求,即接收方接收的数据
2.response表示应答,即发送方得到接收方处理结果后的数据
3.不论发送还是接收方,其request和response都是想要有序列化和反序列化的。想要注意的是,序列化和反序列化是一种结构化的类型,不表示协议,它是协议的有效载荷部分
4.序列化的逻辑:将当前存储的一系列想要被操作的数据,通过存储在out中。通过分隔符进行组合
5.反序列化的逻辑:接受到了in,将in的数据拆分回原来的结构,拆分的依据就是分隔符
4.协议化
std::string enLength(const std::string &text) {std::string send_string = std::to_string(text.size());send_string += LINE_SEP;send_string += text;send_string += LINE_SEP;return send_string; }bool deLength(const std::string &package, std::string *text) {auto pos = package.find(LINE_SEP);if (pos == std::string::npos)return false;std::string text_len_string = package.substr(0, pos);int text_len = std::stoi(text_len_string);*text = package.substr(pos + LINE_SEP_LEN, text_len);return true; }1.规定的协议为:当前序列化的字节流长度大小作为前面的一个字节流且用\r\n来进行分隔序列化的字节流,大概模式为XXX\r\nYYY\r\n
2.加协议enLength:就是将传入的text之前算出text的大小,先加入大小后填入分隔符最后加入序列化的字节流
3.减协议deLength:先找到第一个分隔符,得到整个序列化字节流的大小,随后通过大小长度收录整个序列化的字节流
5.读操作
bool recvPackage(int sock, std::string &inbuffer,std::string *text) {char buffer[1024];while (true){ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);if (n > 0){buffer[n] = 0;inbuffer += buffer;auto pos = inbuffer.find(LINE_SEP);if (pos == std::string::npos)continue;std::string text_len_string = inbuffer.substr(0, pos);int text_len = std::stoi(text_len_string);int total_len = text_len_string.size() + 2 * LINE_SEP_LEN + text_len;if (inbuffer.size() < total_len)continue;*text = inbuffer.substr(0, total_len);inbuffer.erase(0, total_len);break;}elsereturn false;}return true; }3.客户端和服务端的业务逻辑
1.服务端
void handerEnter(int sock, func_t func){std::string inbuffer;while (true){// 1.读取// 1.1读取完整的一个报文std::string req_text;if (!recvRequest(sock, inbuffer, &req_text))return;// 1.2读取完整的报文std::string req_str;if (!deLength(req_text, &req_str))return;// 2.反序列化// 2.1得到一个结构化的请求对象Request req;if (!req.deserialize(req_str))return;// 3.计算业务// 3.1得到一个结构化的响应Response resp;func(req, resp);// 4.对响应进行序列化// 4.1得到一个字符串std::string resp_str;resp.serialize(&resp_str);// 5.然会发送给客户端一个响应// 5.1构造新报文std::string send_string = enLength(resp_str);send(sock, send_string.c_str(), send_string.size(), 0);}}2.客户端
void start(){// 5.要发起链接struct sockaddr_in server;memset(&server, 0, sizeof server);server.sin_family = AF_INET;server.sin_port = htons(_serverport);server.sin_addr.s_addr = inet_addr(_serverip.c_str());if (connect(_sock, (struct sockaddr *)&server, sizeof server) != 0){std::cerr << "connect error: " << errno << " : " << strerror(errno) << std::endl;}else{std::string msg;std::string inbuffer;while (true){std::cout << "mycal>>> ";std::getline(std::cin, msg);//msg要拆分Request req(msg);std::string content;req.serialize(&content);std::string send_string = enLength(content);send(_sock, send_string.c_str(), send_string.size(), 0);std::string package, text;if (!recvPackage(_sock, inbuffer, &package))continue;if (!deLength(package, &text))continue;Response resp;resp.deserialize(text);std::cout << "exitcode: " << resp.exitcode << std::endl;std::cout << "result: " << resp.result << std::endl;}}}
相关文章:
计算机网络(4) --- 协议定制
计算机网络(3) --- 网络套接字TCP_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/132035757?spm1001.2014.3001.5501 目录 1. 协议的基础知识 TCP协议通讯流程 编辑 2.协议 1.介绍 2.手写协议 1.内容 2.接口 …...
【Mybatis】Mybatis架构简介
文章目录 1.整体架构图2. 基础支撑层2.1 类型转换模块2.2 日志模块2.3 反射工具模块2.4 Binding 模块2.5 数据源模块2.6缓存模块2.7 解析器模块2.8 事务管理模块 3. 核心处理层3.1 配置解析3.2 SQL 解析与 scripting 模块3.3 SQL 执行3.4 插件 4. 接口层 1.整体架构图 MyBatis…...
如何使用大模型处理生活繁琐的工作
如果每封电子邮件、每个带有订单、发票、投诉、录用请求或工作申请的 PDF 都可以翻译成机器可读的数据,会怎样?然后可以由 ERP / CRM / LMS / TMS 自动处理吗?无需编程特殊接口。 听起来很神奇?它确实有一些魔力。但最近已成为可…...
RpcController作用浅析
RpcController作用浅析 前面提到了RpcConsumer的实现思路,但是并没说明RpcController有什么作用,不妨看看google::protobuf::RpcController: class PROTOBUF_EXPORT RpcController {public:inline RpcController() {}virtual ~RpcControlle…...
Linux(三):Linux服务器下日常实操命令 (常年更新)
基础命令 cd命令:切换目录 cd :切换当前目录百至其它目录,比如进入/etc目录,则执行 cd /etccd / :在Linux 系统中斜杠“/”表示的是根目录。cd / ,即进入根目录.cd ~:进入用户在该系统的home目录&#…...
强大的截图软件--Snipaste
这里写目录标题 前言Snipaste贴图并置顶标注功能 下载 前言 在工作中,我们经常需要保存当前屏幕的图片,虽然系统总是会自带一些截图工具,但似乎用起来总是不那个顺手,例如我们需要对图片进行一些标注,或者将图片贴在屏…...
LeetCode·每日一题·722. 删除注释·模拟
题目 示例 思路 题意 -> 给定一段代码,将代码中的注释删除并返回。 由于注释只有两种类型: 字符串// 表示行注释,表示//和其右侧的其余字符应该被忽略。字符串/* 表示一个块注释,它表示直到下一个(非重叠&#x…...
npm更新和管理已发布的包
目录 1、更改包的可见性 1.1 将公共包设为私有 编辑 使用网站 使用命令行 1.2 将私有包公开 使用网站 使用命令行 2、将协作者添加到用户帐户拥有的私有包 2.1 授予对Web上私有用户包的访问权限 2.2 从命令行界面授予私有包访问权限 2.3 授予对私有组织包的访问权限…...
如何高效使用Gherkin
背景 时间回到2022年,我参与了一个使用了Flutter技术构建的Web前端项目。在这个项目上,我们小组的目标是实施Flutter前端自动化测试。 彼时,Flutter 2.x刚在Web端发力不久,Flutter Web上的应用和生态才刚刚开始,而在…...
[CKA]考试之调度 pod 到指定节点
由于最新的CKA考试改版,不允许存储书签,本博客致力怎么一步步从官网把答案找到,如何修改把题做对,下面开始我们的 CKA之旅 题目为: Task 创建一个Pod,名字为nginx-kusc00401,镜像地址是nginx…...
git 常用命令有哪些
Git 是我们开发工作中使用频率极高的工具,下面总结下他的基本指令有哪些,顺便温习一下。 前言 一般项目中长存2个分支: 主分支(master) 和开发分支(develop) 项目存在三种短期分支 ࿱…...
算法leetcode|66. 加一(rust重拳出击)
文章目录 66. 加一:样例 1:样例 2:样例 3:提示: 分析:题解:rust:go:c:python:java: 66. 加一: 给定一个由 整数 组成的 非…...
MySQL备份Shell脚本
将此脚本添加到crontab计划中,自动留存最新的两份备份 #!/bin/bash # 数据库配置 DB_HOST"localhost" DB_USER"root" DB_PASS"Sxbdc123!#" DB_NAME"ww"# 备份目录 BACKUP_DIR"/opt/mysqlbak"# 备份文件名称 BA…...
Python批量查字典和爬取双语例句
最近,有网友反映,我的批量查字典工具换到其它的网站就不好用了。对此,我想说的是,互联网包罗万象,网站的各种设置也有所不同,并不是所有的在线字典都可以用Python爬取的。事实上,很多网站为了防…...
uni-app、H5实现瀑布流效果封装,列可以自定义
文章目录 前言一、效果二、使用代码三、核心代码总结前言 最近做项目需要实现uni-app、H5实现瀑布流效果封装,网上搜索有很多的例子,但是代码都是不够完整的,下面来封装一个uni-app、H5都能用的代码。在小程序中,一个个item渲染可能出现问题,也通过加锁来解决问题。 一、…...
vue echart3个饼图
概览:根据UI设计需要做3个饼图且之间有关联,并且处理后端返回的数据。 参考链接: echart 官网的一个案例,3个饼图 实现思路: 根据案例,把数据处理成对应的。 参考代码: 1.处理后端数据&am…...
LEARNING TO EXPLORE USING ACTIVE NEURAL SLAM 论文阅读
论文信息 题目:LEARNING TO EXPLORE USING ACTIVE NEURAL SLAM 作者:Devendra Singh Chaplot, Dhiraj Gandhi 项目地址:https://devendrachaplot.github.io/projects/Neural-SLAM 代码地址:https://github.com/devendrachaplot/N…...
item_search-ks-根据关键词取商品列表
一、接口参数说明: item_search-根据关键词取商品列表,点击更多API调试,请移步注册API账号点击获取测试key和secret 公共参数 请求地址: https://api-gw.onebound.cn/ks/item_search 名称类型必须描述keyString是调用key(http:…...
windows运行WPscan报错:无法打开库libcurl.dll
windows运行WPscan报错:无法打开库libcurl.dll 1.问题背景2.解决方案1.问题背景 在Windows上启动WPScan时: wpscan --url xxx.ru提示如下错误: Could not open library libcurl.dll: �� ������ ��������� ������. . Could not open library libcu...
web前端框架Javascript之JavaScript 异步编程史
早期的 Web 应用中,与后台进行交互时,需要进行 form 表单的提交,然后在页面刷新后给用户反馈结果。在页面刷新过程中,后台会重新返回一段 HTML 代码,这段 HTML 中的大部分内容与之前页面基本相同,这势必造成…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...


