1.应用层

1.1再谈“协议”
约定方案
• 定义结构体来表示我们需要交互的信息;
• 发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按
照相同的规则把字符串转化回结构体;
• 这个过程叫做 "序列化" 和 "反序列化"
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 进程组

5.1.2 组长进程
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 会话
C
#include <unistd.h>
/*
*功能:创建会话
*返回值:创建成功返回 SID, 失败返回-1
*/
pid_t setsid(void);

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

5.4 作业控制
5.4.2 作业的挂起与切回
5.4.3 查看后台执行或挂起的作业
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 作业控制相关的信号
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
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" : "男"
}
#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" : "男"
}
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. 反序列化
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: 北京