当前位置: 首页 > news >正文

网络编程(10)——json序列化

十、day10

今天学习如何使用jsoncpp将json数据解析为c++对象,将c++对象序列化为json数据。jsoncp经常在网络通信中使用,也就是服务器和客户端的通信一般使用json(可视化好);而protobuf一般在服务器之间的通信中使用

jsoncpp下载地址:open-source-parsers/jsoncpp: A C++ library for interacting with JSON. (github.com)

jsoncpp如何配置使用可参考博主

恋恋风辰官方博客​llfc.club/category?catid=225RaiVNI8pFDD5L4m807g7ZwmF#!aid/2Q5XIMAjJ76n2snyNEHstog2W9b

1.如果从github上下载最新版本,cmake编译后使用jsoncpp库,博主恋恋风辰给出的示例代码会造成内存泄漏,应该是最新版的库内部做了一些调整,该问题我没有解决,使用的仍是旧版本的jsoncpp。

2.如果旧版本的jsoncpp没有x64平台,需要自己在管理那里添加设置,确保平台和线程使用的统一性。

3.客户端和服务器做如下调整:

客户端

客户端和服务器都需要包含库目录和包含目录,比如

且需要在链接器→输入→附加依赖项中,添加需要的库

libprotobufd.lib
libprotocd.lib
json_vc71_libmtd.lib

客户端代码做以下调整

#include <boost/asio.hpp>
#include <iostream>
#include <json/json.h>
#include <json/value.h>
#include <json/reader.h>using namespace boost::asio::ip;
using std::cout;
using std::endl;
const int MAX_LENGTH = 1024 * 2; // 发送和接收的长度为1024 * 2字节
const int HEAD_LENGTH = 2;int main()
{try {boost::asio::io_context ioc; // 创建上下文服务// 127.0.0.1是本机的回路地址,也就是服务器和客户端在一个机器上tcp::endpoint remote_ep(address::from_string("127.0.0.1"), 10086); // 构造endpointtcp::socket sock(ioc);boost::system::error_code error = boost::asio::error::host_not_found; // 错误:主机未找到sock.connect(remote_ep, error);if (error) {cout << "connect failed, code is " << error.value() << " error msg is " << error.message();return 0;}Json::Value root;root["id"] = 1001;root["data"] = "hello world";std::string request = root.toStyledString();size_t request_length = request.length();char send_data[MAX_LENGTH] = { 0 };//转为网络字节序int request_host_length = boost::asio::detail::socket_ops::host_to_network_short(request_length);memcpy(send_data, &request_host_length, 2);memcpy(send_data + 2, request.c_str(), request_length);boost::asio::write(sock, boost::asio::buffer(send_data, request_length + 2));char reply_head[HEAD_LENGTH]; // 首先读取对端发送消息的总长度size_t reply_length = boost::asio::read(sock, boost::asio::buffer(reply_head, HEAD_LENGTH));short msglen = 0; // 消息总长度memcpy(&msglen, reply_head, HEAD_LENGTH); // 将消息总长度赋值给msglen//转为本地字节序msglen = boost::asio::detail::socket_ops::network_to_host_short(msglen);char msg[MAX_LENGTH] = { 0 }; // 构建消息体(不含消息总长度)size_t msg_length = boost::asio::read(sock, boost::asio::buffer(msg, msglen));Json::Reader reader;reader.parse(std::string(msg, msg_length), root);std::cout << "msg id is " << root["id"] << " msg is " << root["data"] << endl;std::getchar();}catch (std::exception& e) {std::cerr << "Exception: " << e.what() << endl;}return 0;
}

服务器

服务也通常和客户端做相同的设置,包含库。并在回调读函数中新加这样一段

			//jsoncpp序列化Json::Reader reader;Json::Value root;reader.parse(std::string(_recv_msg_node->_msg, _recv_msg_node->_total_len), root);std::cout << "recevie msg id  is " << root["id"].asInt() << " msg data is "<< root["data"].asString() << endl;root["data"] = "Server has received msg, msg data is " + root["data"].asString();std::string return_str = root.toStyledString();Send_protoc(return_str);

完整的回调读函数如下:

void CSession::handle_read(const boost::system::error_code& error, size_t bytes_transferred,std::shared_ptr<CSession> _self_shared) {if (!error) {// 打印缓存区的数据并将该线程暂停2s//PrintRecvData(_data, bytes_transferred);//std::chrono::milliseconds dura(2000);//std::this_thread::sleep_for(dura);// 每触发一次handale_read,它会返回实际读取的字节数bytes_transferred,copy_len表示已处理的长度,每处理一字节,copy_len便加一int copy_len = 0; // 已经处理的字符数while (bytes_transferred > 0) { // 只要读取到数据就对其处理if (!_b_head_parse) { // 判断消息头部是否已处理,_b_head_parse默认为false// 异步读取到的字节数 + 已接收到的头部长度 < 头部总长度if (bytes_transferred + _recv_head_node->_cur_len < HEAD_LENGTH) { // 收到的数据长度小于头部长度,说明头部还未全部读取// 如果未完全接收消息头,则将接收到的数据复制到头部缓冲区// _recv_head_node->_msg,更新当前头部的接收长度,并继续异步读取剩余数据。memcpy(_recv_head_node->_msg + _recv_head_node->_cur_len, _data + copy_len, bytes_transferred);_recv_head_node->_cur_len += bytes_transferred;// 缓冲区清零,无需更新copy_len追踪已处理的字符数,因为之前读取的数据已经全部写入头部节点,下一个// 读入的消息从头开始(copy_len=0)往头节点写::memset(_data, 0, MAX_LENGTH);// 继续读消息_socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), std::bind(&CSession::headle_read, this,std::placeholders::_1, std::placeholders::_2, _self_shared));return;}// 如果接收到的数据量足够处理消息头部,则计算头部剩余的未接收字节,// 并将其从 _data 缓冲区复制到头部消息缓冲区 _recv_head_node->_msgint head_remain = HEAD_LENGTH - _recv_head_node->_cur_len; // 头部剩余未复制的长度// 填充头部节点memcpy(_recv_head_node->_msg + _recv_head_node->_cur_len, _data + copy_len, head_remain);copy_len += head_remain; // 更新已处理的data长度bytes_transferred -= head_remain; // 更新剩余未处理的长度short data_len = 0; // 获取头部数据(消息长度)memcpy(&data_len, _recv_head_node->_msg, HEAD_LENGTH);//网络字节序转化为本地字节序data_len = boost::asio::detail::socket_ops::network_to_host_short(data_len);cout << "data_len is " << data_len << endl;if (data_len > MAX_LENGTH) { // 判断头部长度是否非法std::cout << "invalid data length is " << data_len << endl;_server->ClearSession(_uuid);return;}_recv_msg_node = std::make_shared<MsgNode>(data_len); // 已知数据长度data_len,构建消息内容载体//消息的长度小于头部规定的长度,说明数据未收全,则先将部分消息放到接收节点里if (bytes_transferred < data_len) {memcpy(_recv_msg_node->_msg + _recv_msg_node->_cur_len, _data + copy_len, bytes_transferred);_recv_msg_node->_cur_len += bytes_transferred;// copy_len不用更新,缓冲区会清零,下一个读入data的数据从头开始写入,copy_len也会被初始化为0::memset(_data, 0, MAX_LENGTH);_socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH),std::bind(&CSession::headle_read, this, std::placeholders::_1, std::placeholders::_2, _self_shared));_b_head_parse = true; //头部处理完成return;}// 接收的长度多于消息内容长度memcpy(_recv_msg_node->_msg + _recv_msg_node->_cur_len, _data + copy_len, data_len);_recv_msg_node->_cur_len += data_len;copy_len += data_len;bytes_transferred -= data_len;_recv_msg_node->_msg[_recv_msg_node->_total_len] = '\0';// cout << "receive data is " << _recv_msg_node->_msg << endl;// protobuf序列化//MsgData msgdata;//std::string receive_data;//msgdata.ParseFromString(std::string(_recv_msg_node->_msg, _recv_msg_node->_total_len));//std::cout << "receive msg id is " << msgdata.id () << " msg data is  " << msgdata.data() << endl;//std::string return_str = "Server has received msg, msg data is " + msgdata.data();//MsgData msgreturn;//msgreturn.set_id(msgdata.id());//msgreturn.set_data(return_str);//msgreturn.SerializeToString(&return_str);//Send_protoc(return_str);// jsoncpp序列化Json::Reader reader;Json::Value root;reader.parse(std::string(_recv_msg_node->_msg, _recv_msg_node->_total_len), root);std::cout << "recevie msg id  is " << root["id"].asInt() << " msg data is "<< root["data"].asString() << endl;root["data"] = "Server has received msg, msg data is " + root["data"].asString();std::string return_str = root.toStyledString();Send_protoc(return_str);//Send(_recv_msg_node->_msg, _recv_msg_node->_total_len); // 回传// 清理已处理的头部消息并重置,准备解析下一条消息_b_head_parse = false;_recv_head_node->Clear();// 如果当前数据已经全部处理完,重置缓冲区 _data,并继续异步读取新的数据if (bytes_transferred <= 0) {::memset(_data, 0, MAX_LENGTH);_socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH),std::bind(&CSession::headle_read, this, std::placeholders::_1, std::placeholders::_2, _self_shared));return;}continue; // 异步读取的消息未处理完,继续填充头节点乃至新的消息节点}//已经处理完头部,处理上次未接受完的消息数据int remain_msg = _recv_msg_node->_total_len - _recv_msg_node->_cur_len;if (bytes_transferred < remain_msg) { //接收的数据仍不足剩余未处理的memcpy(_recv_msg_node->_msg + _recv_msg_node->_cur_len, _data + copy_len, bytes_transferred);_recv_msg_node->_cur_len += bytes_transferred;::memset(_data, 0, MAX_LENGTH);_socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH),std::bind(&CSession::headle_read, this, std::placeholders::_1, std::placeholders::_2, _self_shared));return;}// 接收的数据多于剩余未处理的长度memcpy(_recv_msg_node->_msg + _recv_msg_node->_cur_len, _data + copy_len, remain_msg);_recv_msg_node->_cur_len += remain_msg;bytes_transferred -= remain_msg;copy_len += remain_msg;_recv_msg_node->_msg[_recv_msg_node->_total_len] = '\0';//cout << "receive data is " << _recv_msg_node->_msg << endl;// protobuf序列化//MsgData msgdata;//std::string receive_data;//msgdata.ParseFromString(std::string(_recv_msg_node->_msg, _recv_msg_node->_total_len));//std::cout << "receive msg id is " << msgdata.id() << " msg data is  " << msgdata.data() << endl;//std::string return_str = "Server has received msg, msg data is " + msgdata.data();//MsgData msgreturn;//msgreturn.set_id(msgdata.id());//msgreturn.set_data(return_str);//msgreturn.SerializeToString(&return_str);//Send_protoc(return_str);//jsoncpp序列化Json::Reader reader;Json::Value root;reader.parse(std::string(_recv_msg_node->_msg, _recv_msg_node->_total_len), root);std::cout << "recevie msg id  is " << root["id"].asInt() << " msg data is "<< root["data"].asString() << endl;root["data"] = "Server has received msg, msg data is " + root["data"].asString();std::string return_str = root.toStyledString();Send_protoc(return_str);//此处可以调用Send发送测试//Send(_recv_msg_node->_msg, _recv_msg_node->_total_len);//继续轮询剩余未处理数据_b_head_parse = false;_recv_head_node->Clear();if (bytes_transferred <= 0) {::memset(_data, 0, MAX_LENGTH);_socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH),std::bind(&CSession::headle_read, this, std::placeholders::_1, std::placeholders::_2, _self_shared));return;}continue;}}else {std::cout << "handle read failed, error is " << error.what() << endl;Close();_server->ClearSession(_uuid);}
}

相关文章:

网络编程(10)——json序列化

十、day10 今天学习如何使用jsoncpp将json数据解析为c对象&#xff0c;将c对象序列化为json数据。jsoncp经常在网络通信中使用&#xff0c;也就是服务器和客户端的通信一般使用json&#xff08;可视化好&#xff09;&#xff1b;而protobuf一般在服务器之间的通信中使用 json…...

基于FreeRTOS的STM32多功能手表设计

在智能穿戴设备迅速发展的今天&#xff0c;多功能手表因其便携性和实用性而受到广泛关注。本项目旨在设计一款基于FreeRTOS操作系统的STM32多功能手表&#xff0c;通过实时多任务处理&#xff0c;实现时间显示、多级菜单、万年历、模拟手电筒、温湿度显示、电子闹钟和设置等功能…...

18.Linux-配置DNF仓库

DNF仓库产生背景 在现实的场景中&#xff0c;我们经常要安装一些软件包&#xff0c;但由于现场不提供网络。 需要使用光盘或文件下载的方式去安装。 对于linux有两种离线安装方式&#xff1a;二进制文件安装和源码安装 其中二进制文件是比较简单的安装方式&#xff0c;不同的l…...

GeoPB:高效处理地理空间数据的Protobuf解决方案

在地理信息系统&#xff08;GIS&#xff09;和地理空间数据处理的领域&#xff0c;数据的交换和存储格式至关重要。随着技术的不断发展&#xff0c;如何高效、安全地处理和转换地理空间数据成为了一个核心问题。本文将详细介绍GeoPB——一个基于Protobuf&#xff08;Protocol B…...

华为仓颉语言入门(6):if条件表达式

解锁Python编程的无限可能&#xff1a;《奇妙的Python》带你漫游代码世界 仓颉语言中的 if 表达式用于根据条件的值来决定是否执行相关代码逻辑。if 表达式有三种形式&#xff1a;单分支的 if 表达式、双分支的 if 表达式和嵌套的 if 表达式。 单分支的 if 表达式 单分支的 …...

openlayers中一些问题的解决方案

一、使用地图时可能会出现的需求 1、定位&#xff1a;需要将地图的中心视野&#xff0c;定位到研究区域的中心点&#xff1b; 2、地图蒙版&#xff1a;只研究特定区域&#xff0c;将其他部分区域用蒙层遮罩&#xff0c;突显重点&#xff1b; 3、变色&#xff1a;设置整体的地图…...

java通过redis完成幂等性操作

4 幂等 产生 “重复数据或数据不一致”&#xff08; 假定程序业务代码没问题 &#xff09;&#xff0c;绝大部分就是发生了重复的请求&#xff0c;重复请求是指"同一个请求因为某些原因被多次提交"。导致这个情况会有几种场景&#xff1a; 微服务场景&#xff0c;在…...

48 旋转图像

解题思路&#xff1a; \qquad 这道题同样需要用模拟解决&#xff0c;原地算法要求空间复杂度尽量小&#xff0c;最好为 O ( 1 ) O(1) O(1)。模拟的关键是找到旋转的内在规律&#xff0c;即旋转前后的位置坐标的变化规律。 \qquad 正方形矩阵类似洋葱&#xff0c;可以由不同大小…...

TDengine 签约青山钢铁,实现冶金全流程质量管控智能化

在不锈钢生产领域&#xff0c;企业面临着信息孤岛和数据分散的挑战&#xff0c;尤其在冶炼、连铸和轧钢等关键工艺以及能源管理上&#xff0c;这种现象导致生产要素&#xff08;人、机、料、法、环&#xff09;的分析管理模型难以全面、深入地实施。为了应对这一挑战&#xff0…...

__pycache__文件夹

__pycache__ 文件夹是 Python 在运行时自动生成的目录&#xff0c;用于存储已编译的字节码文件。这些字节码文件以 .pyc 扩展名结尾&#xff0c;用于加速程序的启动时间&#xff0c;因为不需要每次运行时都重新编译源代码。 主要特点 自动生成&#xff1a;__pycache__ 文件夹…...

利用 Local Data 导入文件到 OceanBase 的方法

背景 在很多传统方法中&#xff0c;数据的传输常依赖于csv格式。为了提高传输效率&#xff0c;属于同一张表的多个csv文件往往会被打包成gz文件进行传输。 当gz文件从上游传递到下游后&#xff0c;为了将其中的csv数据导入数据库&#xff0c;一种直接的做法是&#xff1a; 1…...

改变安全策略的五大实践

随着网络威胁形势的加剧&#xff0c;网络安全计划必须不断发展以保护组织的使命。 为了管理这种持续的网络安全发展&#xff0c;应遵循五项关键的安全计划变更管理实践&#xff1a; 1. 识别并吸引受安全风险影响的业务利益相关者 随着新的网络安全风险被发现&#xff0c;受影…...

在MacOS上安装MongoDB数据库

一、安装方法 1.1 安装包安装 首先&#xff0c;打开MongoDB 官网下载安装包&#xff0c;下载链接&#xff1a;https://www.mongodb.com/try/download/community。 根据自己的系统环境自行选择下载的版本。将下载好的 MongoDB 安装包解压缩&#xff0c;并将文件夹名改为 mon…...

负载均衡--会话保持失败原因及解决方案(五)

会话保持失败可能由多种因素导致&#xff0c;以下是一些主要原因及其解释&#xff1a; 一、服务器及网络问题 服务器故障&#xff1a; 服务器出现故障或不稳定&#xff0c;导致无法正确处理会话信息。这可能是由于硬件故障、网络问题或软件错误等引起的。网络问题&#xff1a…...

24 Vue3之集成TailwindCSS

Tailwind CSS Tailwind CSS是一个由js编写的CSS 框架 他是基于postCss 去解析的 官网地址Tailwind CSS 中文文档 - Tailwind CSS - 只需书写 HTML 代码&#xff0c;无需书写 CSS&#xff0c;即可快速构建美观的网站。 | TailwindCSS中文文档 | TailwindCSS中文网 对于PostCSS…...

iOS OC 底层原理之 category、load、initialize

文章目录 category底层结构runtime 执行 category 底层原理添加成员变量 load调用形式系统调用形式的内部原理源码实现逻辑 initialize调用形式源码核心函数&#xff08;由上到下依次调用&#xff09;如果分类实现了 initialize category 底层结构 本质是结构体。struct _cat…...

另外知识与网络总结

一、重谈NAT&#xff08;工作在网络层&#xff09; 为什么会有NAT 为了解决ipv4地址太少问题&#xff0c;到了公网的末端就会有运营商路由器来构建私网&#xff0c;在不同私网中私有IP可以重复&#xff0c;这就可以缓解IP地址太少问题&#xff0c;但是这就导致私有IP是重复的…...

怎样用云手机进行TikTok矩阵运营?

在运营TikTok矩阵时&#xff0c;许多用户常常面临操作复杂、设备过多等问题。如果你也感到操作繁琐&#xff0c;不妨考虑使用云手机。云手机具备丰富的功能&#xff0c;能够帮助电商卖家快速打造高效的TikTok矩阵。接下来&#xff0c;我们将详细解析这些功能如何提升你的运营效…...

RTMP播放器全解析

一、RTMP 播放器概述 &#xff08;一&#xff09;RTMP 播放器的定义与作用 RTMP 播放器是一种专门用于播放采用 RTMP&#xff08;Real Time Messaging Protocol&#xff09;协议的视频流的工具。在当今的流媒体播放领域中&#xff0c;它扮演着至关重要的角色。RTMP 播放器能够…...

定期清洗ip是为了什么?怎么清洗iip

定期清洗IP&#xff08;也称为“IP清理”&#xff09;的目的是确保使用的IP池保持高效、可靠、安全&#xff0c;避免因使用无效或被封禁的IP导致网络操作失败。尤其在数据爬取、负载均衡等使用代理的场景中&#xff0c;定期清洗IP有助于提升整体的性能和数据抓取成功率。 定期…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

论文阅读:Matting by Generation

今天介绍一篇关于 matting 抠图的文章&#xff0c;抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法&#xff0c;已经有很多的工作和这个任务相关。这两年 diffusion 模型很火&#xff0c;大家又开始用 diffusion 模型做各种 CV 任务了&am…...

Axure零基础跟我学:展开与收回

亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:Axure菜单展开与收回 课程视频:...