4.应用层自定义协议与序列化

1.应用层

程序员写的一个个解决我们实际问题, 满足我们日常需求的网络程序, 都是在应用层

1.1再谈“协议”

协议是一种 "约定". socket api 的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的. 如果我们要传输一些 "结构化的数据" 怎么办呢?
其实,协议就是双方约定好的结构化的数据
约定方案
• 定义结构体来表示我们需要交互的信息; 
• 发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按
照相同的规则把字符串转化回结构体; 
• 这个过程叫做 "序列化" 和 "反序列化"

1.2序列化 和 反序列化

只要保证, 一端发送时构造的数据, 在另一端能够正确的进行解析, 就是 ok 的. 
这种约定, 就是 应用层协议。
• 我们要引入序列化和反序列化,我们直接采用现成的方案 -- jsoncpp库• 我们要对 socket 进行字节流的读取处理

 从现在起:如果我们要进行网络协议式的通信,在应用层,强烈建议使用序列化和反序列化的方案。至于直接传结构体的方案,除非特殊场景,否则不建议

序列化和反序列化的优点是解耦!!!

2.重新理解read,write,recv,send和tcp为什么支持全双工

2.1 全双工

所以:
1. 在任何一台主机上,TCP 连接既有发送缓冲区,又有接受缓冲区,所以,在内核
中,可以在发消息的同时,也可以收消息,即全双工
2. 这就是为什么一个 tcp sockfd 读写都是它的原因
3. 实际数据什么时候发,发多少,出错了怎么办,由 TCP 控制,所以 TCP 叫做传
输控制协议

结论:

1. write,read 就是收发消息 ---  write和read是不是把数据发送到了网络中?(no,主要进行的是数据拷贝)(OS把数据发送到网络中,本质也是拷贝)

2. 主机间通信的本质:把发送方的发送缓冲区内部的数据,拷贝到对端的接受缓冲区!

3. 为什么TCP通信的时候,是全双工的?因为有两对发送和接受缓冲区!!!

2.2 面向数据流/面向数据报

 面向数据流(TCP)理解:一次可能读取1.5,0.5 ....个段数据,TCP 能保证字节流的完整性(无丢失、无重复),但不保证消息边界的完整性

而 面向数据报(UDP)每个数据报(Datagram)是独立的 “消息”,包含完整的源 / 目的地址

3.网络版计算器实现

问题:因为TCP是面向字节流的

当读取方在读取的时候,可能读到一个完整的json请求,也可能会读到半个?一个半?5个?5个半请求json串?? --- 全都有可能发生。

read -> 本身并不保证读到的报文的完整性!!!他只保证把数据如果有,就读上来(谁来保证呢??由应用层程序员自己保证!!)【进一步定制协议...】

当我们tcp中读取数据的时候,读到的报文不完整,或者多读了,导致下一个报文不完整了,这个问题叫做 “粘包” 问题 

 Common.hpp

 InetAddr.hpp

 Log.hpp

 main.cc

 makefile

 Mutex.hpp

 NetCal.hpp

 Protocol.hpp

 Socket.hpp

 TcpClient.cc

 TcpServer.hpp

Deamon.hpp

4.关于流式数据的处理

5.进程间关系与守护进程

5.1 进程组

之前我们提到了进程的概念, 其实每一个进程除了有一个进程 ID(PID)之外 还属于一
个进程组。进程组是一个或者多个进程的集合, 一个进程组可以包含多个进程。 每一
个进程组也有一个唯一的进程组 ID(PGID), 并且这个 PGID 类似于进程 ID, 同样是
一个正整数, 可以存放在 pid_t 数据类型中。

5.1.2 组长进程

每一个进程组都有一个组长进程。 组长进程的 ID 等于其进程 ID。我们可以通过 ps
令看到组长进程的现象
Shell
[node@localhost code]$ ps -o pid,pgid,ppid,comm | cat
# 输出结果
PID PGID PPID COMMAND
2806 2806 2805 bash
2880 2880 2806 ps
2881 2880 2806 cat
•  进程组组长的作用: 进程组组长可以创建一个进程组或者创建该组中的进程
•  进程组的生命周期: 从进程组创建开始到其中最后一个进程离开为止。注意: 主要某个进程组中有一个进程存在, 则该进程组就存在, 这与其组长进程是否已经终止无关。

5.2 会话

会话其实和进程组息息相关,会话可以看成是一个或多个进程组的集合, 一个会话可以包含多个进程组。每一个会话也有一个会话 ID(SID)(通常我们都是使用管道将几个进程编成一个进程组
5.2.2 如何创建会话
可以调用 setseid 函数来创建一个会话, 前提是调用进程不能是一个进程组的组长
C
#include <unistd.h>
/*
*功能:创建会话
*返回值:创建成功返回 SID, 失败返回-1
*/
pid_t setsid(void);
该接口调用之后会发生:
调用进程会变成新会话的会话首进程。 此时, 新会话中只有唯一的一个进 程
调用进程会变成进程组组长。 新进程组 ID 就是当前调用进程 ID
该进程没有控制终端。 如果在调用 setsid 之前该进程存在控制终端, 则调用之后会切断联系
需要注意的是: 这个接口如果调用进程原来是进程组组长, 则会报错, 为了避免这种情况, 我们通常的使用方法是先调用 fork 创建子进程, 父进程终止, 子进程继续执行, 因为子进程会继承父进程的进程组 ID, 而进程 ID 则是新分配的, 就不会出现错误的情况。

 

 5.2.2 setsid

setsid是一个非常重要的系统调用和命令行工具,主要用于创建新的会话(session)和进程组(process group)

5.3 控制终端

UNIX 系统中,用户通过终端登录系统后得到一个 Shell 进程,这个终端成为 Shell
进程的控制终端。控制终端是保存在 PCB 中的信息,我们知道 fork 进程会复制 PCB
中的信息,因此由 Shell 进程启动的其它进程的控制终端也是这个终端。默认情况下
没有重定向,每个进程的标准输入、标准输出和标准错误都指向控制终端,进程从标
准输入读也就是读用户的键盘输入,进程往标准输出或标准错误输出写也就是输出到
显示器上。另外会话、进程组以及控制终端还有一些其他的关系:
一个会话可以有一个控制终端,通常会话首进程打开一个终端(终端设备或
伪终端设备)后,该终端就成为该会话的控制终端。
建立与控制终端连接的会话首进程被称为控制进程
一个会话中的几个进程组可被分成一个前台进程组以及一个或者多个后台进
程组
如果一个会话有一个控制终端,则它有一个前台进程组,会话中的其他进程
组则为后台进程组。
无论何时进入终端的中断键(ctrl+c)或退出键(ctrl+\),就会将中断信号
发送给前台进程组的所有进程。
如果终端接口检测到调制解调器(或网络)已经断开,则将挂断信号发送给
控制进程(会话首进程)。
这些特性的关系如下图所示:

5.4 作业控制

作业是针对用户来讲,用户完成某项任务而启动的进程,一个作业既可以只包含一个进程,也可以包含多个进程,进程之间互相协作完成任务, 通常是一个进程管道。
Shell 分前后台来控制的不是进程而是作业 或者进程组。一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成,Shell 可以同时运⾏一个前台作业和任意多个后台作业,这称为作业控制

5.4.2 作业的挂起与切回

(1) 作业挂起
我们在执⾏某个作业时,可以通过 Ctrl+Z 键将该作业挂起,然后 Shell 会显示相关的作业号、状态以及所执⾏的命令信息。现通过 Ctrl+Z 将作业挂起, 该作业状态已经变为了停止状态
(2) 作业切回
如果想将挂起的作业切回,可以通过 fg 命令,fg 后面可以跟作业号作业的命令名称。如果参数缺省则会默认将作业号为 1 的作业切到前台来执⾏,若当前系统只有一个作业在后台进⾏,则可以直接使用 fg 命令不带参数直接切回

5.4.3 查看后台执行或挂起的作业

我们可以直接通过输入 jobs 命令查看本用户当前后台执⾏或挂起的作业
▪  参数-l 则显示作业的详细信息
▪  参数-p 则只显示作业的 PID
例如, 我们先在后台及前台运⾏两个作业, 并将前台作业挂起, 来用 jobs 命令
查看作业相关的信息:
Shell
# 在后台运行一个作业 sleep
[node@localhost code]$ sleep 300 &
# 运行刚才的死循环可执行程序
[node@localhost code]$ ./test
# 键入 Ctrl + Z 挂起作业
# 使用 jobs 命令查看后台及挂起的作业
[node@localhost code]$ jobs -l运⾏结果如下所示:
Shell
# 结果依次对应作业号 默认作业 作业状态 运行程序信息
[1]- 2265 运行中 sleep 300 &
[2]+ 2267 停止 ./test7

5.4.4 作业控制相关的信号

键入 Ctrl + Z 可以将前台作业挂起,实际上是将 STGTSTP 信号发送至前台进程组作业中的所有进程, 后台进程组中的作业不受影响。 在 unix系统中, 存在 3 个特殊字符可以使得终端驱动程序产生信号, 并将信号发送至前台进程组作业, 它们分别是:
Ctrl + C: 中断字符, 会产生 SIGINT 信号
Ctrl + \: 退出字符, 会产生 SIGQUIT 信号
Ctrl + Z:挂起字符, 会产生 STGTSTP 信号
终端的 I/O(即标准输入和标准输出)和终端产生的信号总是从前台进程组作业连接打破实际终端

5.5 守护进程

附录:
1. Jsoncpp

命令 ls /usr/include/jsoncpp/json/ 用于查看 Linux 系统中 JSONCpp 库的头文件目录

 Jsoncpp 是一个用于处理 JSON 数据的 C++ 库。它提供了将 JSON 数据序列化为字符串以及从字符串反序列化为 C++ 数据结构的功能

C++
ubuntu:sudo apt-get install libjsoncpp-dev
Centos: sudo yum install jsoncpp-devel
Jsoncpp 提供了多种方式进行序列化:
1. 使用 Json::Value toStyledString 方法:
        ○ 优点:将 Json::Value 对象直接转换为格式化的 JSON 字符串
C++
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";std::string s = root.toStyledString();std::cout << s << std::endl;return 0;
}$ ./test.exe
{"name" : "joe","sex" : "男"
}
2. 使用 Json::StreamWriter
        优点:提供了更多的定制选项,如缩进、换行符等。
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>
int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";Json::StreamWriterBuilder wbuilder; // StreamWriter 的
工厂std::unique_ptr<Json::StreamWriter>
writer(wbuilder.newStreamWriter());std::stringstream ss;writer->write(root, &ss);std::cout << ss.str() << std::endl;return 0;
}$ ./test.exe
{"name" : "joe","sex" : "男"
}
3. 使用 Json::FastWriter
        优点:比 StyledWriter 更快,因为它不添加额外的空格和换行符。
C++
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>
int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";Json::FastWriter writer;std::string s = writer.write(root);std::cout << s << std::endl;return 0;
}$ ./test.exe
{"name":"joe","sex":"男"}#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>
int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";// Json::FastWriter writer;Json::StyledWriter writer;std::string s = writer.write(root);std::cout << s << std::endl;return 0;
}$ ./test.exe
{"name" : "joe","sex" : "男"
}

2. 反序列化

1. 使用 Json::Reader
        ○ 优点:提供详细的错误信息和位置,方便调试。
C++
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
int main() {// JSON 字符串std::string json_string = "{\"name\":\"张三\",
\"age\":30, \"city\":\"北京\"}";// 解析 JSON 字符串Json::Reader reader;Json::Value root;// 从字符串中读取 JSON 数据bool parsingSuccessful = reader.parse(json_string,
root);if (!parsingSuccessful) {// 解析失败,输出错误信息std::cout << "Failed to parse JSON: " <<reader.getFormattedErrorMessages() << std::endl;return 1;
}// 访问 JSON 数据std::string name = root["name"].asString();int age = root["age"].asInt();std::string city = root["city"].asString();// 输出结果std::cout << "Name: " << name << std::endl;std::cout << "Age: " << age << std::endl;std::cout << "City: " << city << std::endl;return 0;
}
$ ./test.exe
Name: 张三
Age: 30
City: 北京

3. Json::Value

Json::Value Jsoncpp 库中的一个重要类,用于表示和操作 JSON 数据结构。以下是一些常用的 Json::Value 操作列表(具体的看课件)

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

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

相关文章

【QT搭建opencv环境】

本文参考以下文章&#xff1a; https://blog.csdn.net/weixin_43763292/article/details/112975207 https://blog.csdn.net/qq_44743171/article/details/124335100 使用软件 QT 5.14.2下载地址&#xff1a;download.qt.io 选择版本&#xff1a;Qt 5.14.2 Qt 5.14.2百度网盘链接…

golang--函数栈

一、函数栈的组成结构&#xff08;栈帧&#xff09; 每个函数调用对应一个栈帧&#xff0c;包含以下核心部分&#xff1a; 1. 参数区 (Arguments) 位置&#xff1a;栈帧顶部&#xff08;高地址端&#xff09;内容&#xff1a; 函数调用时传入的参数按从右向左顺序压栈&#xff…

【FAQ】创建Dynamics 365 Sales环境

参考文章&#xff1a;5 分钟内安装 Dynamics 365 Sales 步骤 1&#xff1a;访问 Power Platform 管理中心 导航到make.powerapps.com&#xff0c;然后点击右上角的齿轮图标。选择管理中心&#xff0c;或者访问aka.ms/ppac访问 Power Platform 管理中心。 第 2 步&#xff1a…

【数据库】使用Sql Server将分组后指定字段的行数据转为一个字段显示,并且以逗号隔开每个值,收藏不迷路

大家好&#xff0c;我是全栈小5&#xff0c;欢迎来到《小5讲堂》。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录前言示例数据集数…

7.项目起步(1)

1&#xff0c;项目起步-初始化项目并使用git管理创建项目并精细化配置src目录调整git 管理项目2项目起步-配置别名路径联想提示什么是别名路径联想提示如何进行配置 &#xff08;自动配置了&#xff09;{"compilerOptions" : {"baseUrl" : "./",…

【C++详解】深入解析继承 类模板继承、赋值兼容转换、派生类默认成员函数、多继承与菱形继承

文章目录一、继承概念二、继承定义定义格式继承后基类成员访问方式的变化类模板的继承三、基类和派⽣类间的转换(赋值兼容转换)四、继承中的作用域隐藏规则两道笔试常考题五、派生类的默认成员函数四个常见默认成员函数实现⼀个不能被继承的类六、继承与友元七、继承与静态成员…

加法器 以及ALU(逻辑算术单元)

加法器框架&#xff0c;首先介绍原理&#xff0c;然后引入一位加法器最后再引入多位加法器最后引入带符号的加法器这一节涉及到的硬件电路的知识理解就好&#xff0c;实在看不懂就跳过&#xff0c;但是封装以后的功能必须看懂。这是一个一般的加法过程涉及到的必要元素图中已经…

设计模式实战:自定义SpringIOC(亲手实践)

上一篇&#xff1a;设计模式实战&#xff1a;自定义SpringIOC&#xff08;理论分析&#xff09; 自定义SpringIOC&#xff08;亲手实践&#xff09; 上一篇文章&#xff0c;我们介绍了SpringIOC容器的核心组件及其作用&#xff0c;下面我们来动手仿写一个SpringIOC容器&#…

力扣面试150(42/150)

7.28 20. 有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一…

基于黑马教程——微服务架构解析(二):雪崩防护+分布式事务

之前的两篇文章我们介绍了微服务的基础概念及其服务间通信机制。本篇将深入探讨微服务的核心保障&#xff1a;服务保护与分布式事务。一、微服务保护问题描述&#xff1a; 在一个购物车的微服务中&#xff0c;倘若某一项服务&#xff08;服务A&#xff09;同一时刻访问的数据十…

LeetCode: 429 N叉树的层序遍历

题目描述给定一个 N 叉树&#xff0c;返回其节点值的层序遍历&#xff08;即从左到右&#xff0c;逐层访问每一层的所有节点&#xff09;。示例输入格式&#xff08;层序序列化&#xff09;&#xff1a;输入示意&#xff1a;1/ | \3 2 4/ \5 6输出&#xff1a;[[1], [3,2,4…

使用phpstudy极简快速安装mysql

使用 phpStudy 极简快速安装 MySQL 的完整指南&#xff1a; 一、phpStudy 简介 phpStudy 是一款 Windows 平台下的 PHP 环境集成包&#xff0c;包含&#xff1a; Apache/Nginx PHP 5.x-7.x MySQL 5.5-8.0 phpMyAdmin 二、安装步骤 1. 下载安装包 访问官网下载&#xf…

git lfs使用

apt install git lfs 或者下载二进制文件加到环境变量 https://github.com/git-lfs/git-lfs/releases git lfs install git lfs clone huggingface文件路径 如果访问不了hugggingface.co用hf-mirror.com替代&#xff0c;国内下载速度还是挺快的 先按照pip install modelscope m…

6、CentOS 9 安装 Docker

&#x1f433; CentOS 9 安装 Docker 最全图文教程&#xff08;含镜像源优化与常见问题解决&#xff09;标签&#xff1a;CentOS 9、Docker、容器技术、开发环境、国内镜像源 适合读者&#xff1a;后端开发、运维工程师、Linux 初学者&#x1f4cc; 前言 在 CentOS 9 上安装 Do…

SystemV消息队列揭秘:原理与实战

目录 一、消息队列的基本原理 1、基本概念 2、基本原理 3、消息类型的关键作用 4、重要特性总结 5、生命周期管理 6、典型应用场景 二、System V 消息队列的内核数据结构 1、消息队列的管理结构 msqid_ds&#xff08;消息队列标识符结构&#xff09; 关键字段解析 2…

5 分钟上手 Firecrawl

文章目录Firecrawl 是什么&#xff1f;本地部署验证mcp安装palyground&#x1f525; 5 分钟上手 FirecrawlFirecrawl 是什么&#xff1f; 一句话&#xff1a; 开源版的 “最强网页爬虫 清洗引擎” • 自动把任意网页 → 结构化 Markdown / JSON • 支持递归整站抓取、JS 渲染…

算法训练营day31 贪心算法⑤56. 合并区间、738.单调递增的数字 、968.监控二叉树

贪心算法的最后一篇博客&#xff01;前面两道题都是比较简单的思路&#xff0c;重点理解一下最后一道题即可。有一说一&#xff0c;进入到贪心算法这一章节之后&#xff0c;我的博客里和代码注释里的内容明显少了很多&#xff0c;因为很多贪心的题目我觉得不需要很复杂的文字说…

Jenkins流水线部署+webhook2.0

文章目录1. 环境2. 用到的插件3. 流水线部署脚本1. 环境 Centos7Jenkins2.5.0JDKopen17阿里云仓库 注意&#xff1a;这个版本兼容需要特别注意&#xff0c;要不然会很麻烦 2. 用到的插件 Generic Webhook Trigger 3. 流水线部署脚本 兼容钩子部署&#xff08;webhook&…

IDM下载失败排查

网络连接问题排查检查网络连接是否稳定&#xff0c;确保能够正常访问互联网 测试其他下载工具或浏览器是否能够正常下载 尝试关闭防火墙或杀毒软件&#xff0c;排除安全软件拦截的可能性代理和VPN设置检查确认IDM的代理设置是否正确&#xff0c;是否与系统代理一致 检查是否使用…

Anaconda安装时的几个操作

一、安装Anaconda 其实Anaconda的安装比较简单&#xff0c;点击next就好了。在安装中需要注意以下两点&#xff1a; 1、选择安装路径 在安装时&#xff0c;路径最好选择非C盘&#xff0c;且路径中不要出现中文&#xff0c;以免后期运行代码时出现不必要的错误。 我安装时&…