文章目录
- 一、应用层
- 1、协议
- 2、序列化 && 反序列化
- 3、通过Json库进行数据的序列化 && 反序列化
- Json::Value类
- Json::Reader类
- Json::Writer类
- 二、为什么read、write、recv、send和Tcp支持全双工?
- 发数据的本质:
- tcp支持全双工通信的原因:
- 为什么IO函数要阻塞?
- 其他:
- 因为面向字节流,可能读取不了一个完成的请求,那如何保证在主机中保证处理的是一个完整的请求?
- 因为面向字节流,可能读取不了一个完成的请求,那如何保证在主机中保证处理的是一个完整的请求?
一、应用层
1、协议
- 协议本质是一种约定。
- 协议就是双方约定好的结构化数据。
2、序列化 && 反序列化
在用户在网络中发送的信息类型不都是字符串,有可能是整型,浮点数,自定义类型等等,将不同的类型通过网络发送给另外一个客户端,然后进行识别明显是比较困难的,为了解决这种事情,我们把发送的消息进行序列化和反序列化来对信息进行封装和解封。
3、通过Json库进行数据的序列化 && 反序列化
Json::Value类
operator[]
:通过键名或索引访问JSON对象中的元素。append
:向JSON数组中添加元素。asString
、asInt
、asFloat
、asBool
等:将Json::Value对象转换为不同的数据类型。type()
:获取Json::Value对象的类型。
// 创建一个Json::Value 对象
Json::Value root;
// 通过键值访问Json对象元素,如果没有键值对应的元素则新建
root["name"] = "zhangsan";
root["age"] = 18;
root["year" ] = 2024;
// 向数组中添加键值对
// 创建一个Json::Value对象,并初始化为数组类型
Json::Value root(Json::arrayValue);
// 使用append方法向数组中添加元素
root.append("Hello"); // 添加一个字符串
root.append(123); // 添加一个整数
root.append(45.67); // 添加一个浮点数
// 将Json::Value对象转换为不同的数据类型
// asString、asInt、asFloat、asBool等
int age = root["age"].asInt();
std::string name = root["name"].asString();
// 获取Json::Value对象的类型
// Null:表示JSON中的null值。
// String:表示JSON中的字符串值。
// Number:表示JSON中的数字值,这通常包括整数和浮点数。不过,在某些实现中,可能会进一步区分整数(Int)和浮点数(Float或Double)。
// Boolean:表示JSON中的布尔值(true或false)。
// Array:表示JSON中的数组,数组可以包含多个JSON值,这些值的类型可以不同。
// Object:表示JSON中的对象,对象由键值对组成,其中键是字符串,值是任意的JSON值。
// ...
Json::ValueType type = root.type();
// 输出,测试
Json::FastWriter writer;
std::string str = writer.write(root);
std::cout << str << std::endl;
Json::Reader类
用于将JSON格式的字符串解析为Json::Value对象。
parse
:解析JSON字符串,并将其存储在Json::Value对象中。
// JSON格式的字符串
std::string jsonStr = R"({"name": "John Doe", "age": 30, "is_student": false, "scores": [90, 85, 95]})";
// 创建一个Json::Value对象来存储解析后的JSON数据
Json::Value root;
// 创建一个Json::Reader对象来解析JSON字符串
Json::Reader reader;
// 使用parse方法解析JSON字符串
bool parsingSuccessful = reader.parse(jsonStr, root);
// 检查解析是否成功
if (!parsingSuccessful)
{
// 如果解析失败,输出错误信息
std::cout << "Failed to parse JSON"
<< std::endl
<< reader.getFormattedErrorMessages() << std::endl;
return 1;
}
// 解析成功后,可以使用root对象来访问JSON数据
std::string name = root["name"].asString();
int age = root["age"].asInt();
bool isStudent = root["is_student"].asBool();
// 访问数组中的元素
Json::Value scores = root["scores"];
for (int i = 0; i < scores.size(); ++i)
{
std::cout << "Score " << i + 1 << ": " << scores[i].asInt() << std::endl;
}
// 输出一些基本信息
std::cout << "Name: " << name << std::endl;
std::cout << "Age: " << age << std::endl;
std::cout << "Is Student: " << std::boolalpha << isStudent << std::endl;
Json::Writer类
- 功能:Json::Writer是一个抽象基类,用于将Json::Value对象序列化为JSON格式的字符串。通常不会直接使用,而是使用其子类如Json::StyledWriter或Json::FastWriter。
- 子类:
- Json::StyledWriter:生成格式化的JSON字符串,易于阅读。
- Json::FastWriter:生成紧凑的JSON字符串,没有额外的空格和换行符。
Json::Value root;
root["name"] = "zhangsan";
root["age"] = 18;
root["year"] = 2024;
Json::FastWriter fast_write;
Json::StyledWriter styledwriter;
std::string str1 = fast_write.write(root);
std::cout << str1 << std::endl;
std::cout << "------------------------------" << std::endl;
std::string str2 = styledwriter.write(root);
std::cout << str2 << std::endl;
二、为什么read、write、recv、send和Tcp支持全双工?
- 一个文件描述符fd,代表一个连接。一个连接,有两个缓冲区,发送缓冲区和接收缓冲区。
- read、write、send、recv**本质都是拷贝函数**。
发数据的本质:
从发送方的发送缓冲区把数据通过协议栈和网络拷贝给接收方的接收缓冲区。
tcp支持全双工通信的原因:
有两个缓冲区,读写不受到冲突。
(传输控制协议!什么时候发?发多少?出错了怎么办?均有tcp决定。)
为什么IO函数要阻塞?
本质就是在维护同步关系!
其他:
- 网络层、传输层 属于 os。
- 面向字节流:客户端发的,不一定全部是服务器收的。— 也就是说客户端可能发送的不是一个完整报文。
因为面向字节流,可能读取不了一个完成的请求,那如何保证在主机中保证处理的是一个完整的请求?
- 网络层、传输层 属于 os。
- 面向字节流:客户端发的,不一定全部是服务器收的。— 也就是说客户端可能发送的不是一个完整报文。
因为面向字节流,可能读取不了一个完成的请求,那如何保证在主机中保证处理的是一个完整的请求?
手动分割完整的报文。