当前位置: 首页 > 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有助于提升整体的性能和数据抓取成功率。 定期…...

谁能给我一个ai现在无法替代画师的理由?

小白可做&#xff01;全自动AI影视解说一键成片剪辑工具https://docs.qq.com/doc/DYnl6d0FLdHp0V2ll 如何看待现如今的AI绘画 哎呀玫瑰花来了&#xff0c;所有花式都要玩完了。 我相信大家在网上已经看过了太多惊为天人的AI绘画作品&#xff0c;有人抵制&#xff0c;有人支持&a…...

深入理解MySQL InnoDB中的B+索引机制

目录 一、InnoDB中的B 树索引介绍 二、聚簇索引 &#xff08;一&#xff09;使用记录主键值的大小进行排序 页内记录排序 页之间的排序 目录项页的排序 &#xff08;二&#xff09;叶子节点存储完整的用户记录 数据即索引 自动创建 &#xff08;三&#xff09;聚簇索引…...

语言的输入

编程语言提供最基本的输入输出&#xff0c;输入一个预期的数据也不是看起来那么简单&#xff0c;如下一一展开。 不同输入形式 C语言scanf提供格式串输入&#xff0c;程序员负责配置正确的格式&#xff0c;比如%d整型&#xff0c;%s为字符串。可能出现格式串和变量格式、个数不…...

2024年中国电子学会青少年软件编程(Python)等级考试(二级)核心考点速查卡

考前练习 2024年03月中国电子学会青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;二级&#xff09;答案 解析 2024年06月中国电子学会青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;二级&#xff09;答案 解析 知识点描述 …...

OpenCV系列教程二:基本图像增强(数值运算)、滤波器(去噪、边缘检测)

文章目录 一、基本图像增强&#xff08;数值运算&#xff09;1.1 加法 &#xff08;cv2.add&#xff09;1.1.1 图像与标量相加&#xff08;调节亮度&#xff09;1.1.2 图像与图像相加&#xff08;两个图像shape要相同&#xff09;1.1.3 图像的加权加法&#xff08;渐变切换&…...

什么是文件完整性监控(FIM)

组织经常使用基于文件的系统来组织、存储和管理信息。文件完整性监控&#xff08;FIM&#xff09;是一种用于监控和验证文件和系统完整性的技术&#xff0c;识别用户并提醒用户对文件、文件夹和配置进行未经授权或意外的变更是 FIM 的主要目标&#xff0c;有助于保护关键数据和…...

分库分表还是分布式?如何用 OceanBase的单机分布式一体化从根本上解决问题

随着企业业务规模的不断增长&#xff0c;单机集中式的数据库系统逐渐难以承载企业日益增长的数据存储与处理需求。因此&#xff0c;MySQL 的分库分表方案成为了众多企业应对数据存储量激增及数据处理能力需求扩张的“止痛药”。尽管这一方案短期内有效缓解了企业面临的大规模数…...

怎么查看网站是否被谷歌收录,哪些因素影响着网站是否被谷歌收录

一、怎么查看网站是否被谷歌收录 查看网站是否被谷歌收录&#xff0c;有多种方法可供选择&#xff0c;以下是几种常用的方式&#xff1a; 1.使用“site:”指令&#xff1a; 在谷歌搜索引擎的搜索框中输入“site:你的域名网址”&#xff08;注意使用英文冒号&#x…...

【RabbitMQ】面试题

在本篇文章中&#xff0c;主要是介绍RabbitMQ一些常见的面试题。对于前几篇文章的代码&#xff0c;都已经在码云中给出&#xff0c;链接是mq-test: 学习RabbitMQ的一些简单案例 (gitee.com)&#xff0c;如果存在问题的话欢迎各位提出&#xff0c;望共同进步。 MQ的作用以及应用…...

Python软体中使用TensorFlow实现一个简单的神经网络:从零开始

使用TensorFlow实现一个简单的神经网络:从零开始 在现代数据科学和机器学习领域,神经网络是一个强大的工具。TensorFlow是一个广泛使用的开源库,专门用于机器学习和深度学习。本文将详细介绍如何使用TensorFlow实现一个简单的神经网络。我们将从基础概念开始,逐步深入到代…...