计算机网络(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;}}}

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

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

相关文章

MVC配置原理

如果你想保存springboot的mvc配置并且还想自己添加自己的配置就用这个。 视图解析器原理&#xff0c;它会从IOC容器里获取配置好视图解析器的配置类里的视图解析器集合&#xff0c; 然后遍历集合&#xff0c;生成一个一个的视图对象&#xff0c;放入候选 视图里&#xff0c;…

Spark、RDD、Hive 、Hadoop-Hive 和传统关系型数据库区别

Hive Hadoop Hive 和传统关系型数据库区别 Spark 概念 基于内存的分布式计算框架 只负责算 不负责存 spark 在离线计算 功能上 类似于mapreduce的作用 MapReduce的缺点 运行速度慢 &#xff08;没有充分利用内存&#xff09;接口比较简单&#xff0c;仅支持Map Reduce功能…

微信云开发-数据库操作

文章目录 前提初始化数据库插入数据查询数据获取一条数据获取多条数据查询指令 更新数据更新指令 删除数据总结 前提 首先有1个集合(名称:todos). 其中集合中的数据为: {// 计划描述"description": "learn mini-program cloud service",// 截止日期"…

【Linux】操作系统与冯诺依曼体系——深度解析(软硬件层面)

​ 前言 大家好吖&#xff0c;欢迎来到 YY 滴 Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过Linux的老铁&#xff0c;从软硬件层面向大家介绍操作系统与冯诺依曼体系&#xff0c; 主要内容含&#xff1a; 欢迎订阅 YY滴Linux专栏&#xff01;更多干货持…

学习笔记|简单分享一下自建Gravatar镜像

目录 前言 Gravatar 使用 思路 操作 步骤一&#xff1a;注册或登录华为云 步骤二&#xff1a;创建委托账号 步骤三&#xff1a;创建OBS桶 步骤四&#xff1a;数据回源配置 步骤五&#xff1a;配置生命周期规则 步骤六&#xff1a;绑定自定义域名 步骤七&#xff1a…

吉利科技携手企企通,打造集团化数智供应链系统

近日&#xff0c;吉利科技集团有限公司&#xff08;以下简称“吉利科技”&#xff09;联合企企通成功召开SRM采购供应链管理项目启动会。企企通与吉利科技高层、项目负责人与团队成员出席此次启动会。 双方将携手在企业供应商全生命周期管理、采购全流程、电子招投标、采购分析…

【LeetCode 75】第二十三题(2352)相等行列对

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目很简洁&#xff0c;就是要我们寻找行与列相同的对数。相同行与列不仅是要元素相同&#xff0c;还需要顺序也一样&#xff08…

MySQL面试1

Mysql的面试突击1 Mysql的体系结构是什么样子的&#xff08;查询语句怎么进行执行的&#xff09; mysql的架构&#xff1a;单进程多线程的架构模式 CLient -----> Server架构 Mysql的链接方式有没有性能优化的点 2个点 查询缓存(Query Cache) MySQL 内部自带了一个缓存模…

mysql转sqlite3

在项目中需要将mysql迁移到sqlite3中&#xff0c;此时需要作数据转换 准备工作 下载mysql2sqlite转换工具 https://github.com/dumblob/mysql2sqlite/archive/refs/heads/master.zip 下载sqlite3 https://www.sqlite.org/download.html 转换 命令行中输入如下命令 1、cd …

计算机网络(5) --- http协议

计算机网络&#xff08;4&#xff09; --- 协议定制_哈里沃克的博客-CSDN博客协议定制https://blog.csdn.net/m0_63488627/article/details/132070683?spm1001.2014.3001.5501 目录 1.http协议介绍 1.协议的延申 2.http协议介绍 3.URL 4.urlencode和urldecode 2.HTTP协…

NeRF-SLAM: Real-Time Dense Monocular SLAM with Neural Radiance Fields 论文阅读

论文信息 题目&#xff1a;NeRF-SLAM: Real-Time Dense Monocular SLAM with Neural Radiance Fields 作者&#xff1a;Antoni Rosinol, John J. Leonard&#xff0c; Luca Carlone 代码&#xff1a;https://github.com/ToniRV/NeRF-SLAM 来源&#xff1a;arxiv 时间&#xff…

Java课设--学生信息管理系统(例2)

文章目录 前提一、运行效果二、代码获取 前言 首先确定自己的JDBC连接数据库已经完成&#xff0c;不懂可以看看其他博主的解析。 我使用的是SQL Server数据库&#xff0c;数据库名称为stu,账号为sa,密码为123456 数据库的表为student表&#xff0c;内容如下&#xff1a; 一、…

第一百二十三天学习记录:C++提高:STL-vector容器(下)(黑马教学视频)

vector插入和删除 功能描述&#xff1a; 对vector容器进行插入、删除操作 函数原型&#xff1a; push_back(ele); //尾部插入元素ele pop_back(); //删除最后一个元素 insert(const_iterator pos, ele); //迭代器指向位置pos插入元素ele insert(const_iterator pos, int cou…

MySQL数据库安装(二)

夕阳留恋的不是黄昏&#xff0c;而是朝阳 上一章简单介绍了MySQL数据库概述(一), 如果没有看过, 请观看上一章 一. MySQL 卸载 一.一 停止MySQL服务 在卸载之前&#xff0c;先停止MySQL8.0的服务。按键盘上的“Ctrl Alt Delete”组合键&#xff0c;打开“任务管理器”对话…

我设置了IIS的默认文档为什么还是提示403 - 禁止访问: 访问被拒绝。

我设置了IIS的默认文档为什么还是提示403 - 禁止访问: 访问被拒绝。 这个问题我是在处理dedeCMS站点时发现的问题 解决方法&#xff1a; 打开IIS》应用程序池》&#xff08;找到你的站点应用池&#xff09;》右键》基本设置》版本&#xff1a;选择2.0》管道&#xff1a;选择“…

75. 颜色分类

题目链接&#xff1a;力扣 解题思路&#xff1a;因为整个nums数组中只有0&#xff0c;1&#xff0c;2三个数组成。对nums升序排序后&#xff0c;0一定都在数组的最左边&#xff0c;2一定都在数组的最右边&#xff0c;1在数组的中间。那么只需要将0移动到数组的左边&#xff0c;…

c++画出分割图像,水平线和垂直线

1、pca 找到图像某个区域的垂直线&#xff0c;并画出来 // 1、 斑块的框 血管二值化图&#xff0c;pca 找到垂直血管壁的直线, 还是根据斑块找主轴方向吧// Step 1: 提取斑块左右范围内的血管像素点坐标&#xff0c;std::vector<cv::Point> points;for (int y 0; y <…

亿发江西中小型制造企业信息化建设解决方案,2023数字化转型升级

实体经济在经济中的重要性愈发凸显&#xff0c;江西省作为制造业强省&#xff0c;要实现制造业经济高质量发展&#xff0c;信息技术与制造业的深度汇合是不可或缺的关键路径。在这个制造业转型升级的浪潮中&#xff0c;中小企业成为了江西省制造业转型的焦点。让我们深入探讨一…

【java】final

final final修饰属性fianl修饰方法fianl修饰类 final修饰属性 final可以修饰变量&#xff1a;变量的值一旦初始化后无法修改 final可以修饰属性&#xff1a;那么JVM无法自动进行初始化&#xff0c;需要自己进行初始化, 属性值不能发生变化。 public class chapter15 {public …

爬虫010_列表高级_添加_append_extend_修改_查询_in_not int_删除_del_pop_remove---python工作笔记029

然后再来看列表操作 首先添加append方法 然后插入,坐标是要插入的下标,右边是插入的内容 看结果 1,2,3,4,5,6 然后这个extend,是逐个插入,放到后边 然后是修改,直接对下标赋值 看结果</