前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >cJSON使用介绍以及如何利用cJSON在服务端和客户端中进行数据传输

cJSON使用介绍以及如何利用cJSON在服务端和客户端中进行数据传输

原创
作者头像
晨星成焰
发布2024-07-27 15:05:58
2211
发布2024-07-27 15:05:58
举报
文章被收录于专栏:网络编程C++入门基础知识

cJSON简介:一种高效且易于使用的 JSON 解析器和生成器

在当今的软件开发领域中,JSON(JavaScript Object Notation)已成为数据交换的标准格式之一。由于其简洁、易读和跨平台的特性,它被广泛应用于Web应用程序、移动应用和物联网设备中。对于需要在C语言环境中处理JSON的应用程序而言,cJSON 是一个非常实用且流行的库。

如何使用cJSON进行数据交互?

首先通过github地址

https://github.com/DaveGamble/cJSON

将其中的

下载至想要引入cJSON的项目里就行

如图所示

cJSON介绍:

创建 JSON 数据:

代码语言:c
复制
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);

cJSON_CreateNull(): 创建一个 null 类型的 JSON 对象。

cJSON_CreateTrue() / cJSON_CreateFalse(): 创建一个布尔值类型的 JSON 对象。

cJSON_CreateNumber(double num): 创建一个数字类型的 JSON 对象。

cJSON_CreateString(const char *str): 创建一个字符串类型的 JSON 对象。

cJSON_CreateArray(): 创建一个 JSON 数组。

cJSON_CreateObject(): 创建一个 JSON 对象。

添加数据

这里只介绍cJSON_AddItemToArray和cJSON_AddItemToObject以及其宏定义相关的简单使用例

代码语言:c
复制
/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
extern void	cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);	/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);

/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))

cJSON_AddItemToArray

添加数组元素到数组

将 item 添加到 array 中。item 可以是任意类型的 cJSON 结构体(字符串、数字、对象、数组等)。

cJSON_AddItemReferenceToArray

将 item 的引用添加到 array 中。与 cJSON_AddItemToArray 不同的是,这里不复制 item,而是直接引用它,这就意味着cJSON_Delete不会去删除这个元素的child或者valuestring属性,因此当这些属性在其他地方使用的时候,不用担心重复释放内存的事情发生。

AddItemToArray使用例子

代码语言:cpp
复制
	cJSON* alphabet = cJSON_CreateArray();
	cJSON_AddItemToArray(alphabet, cJSON_CreateString("A"));
	cJSON_AddItemToArray(alphabet, cJSON_CreateString("B"));
    cJSON_AddItemToArray(alphabet, cJSON_CreateString("C"));
	const char* strAlphabet = cJSON_Print(alphabet);

	std::cout << strAlphabet <<std::endl;

cJSON_AddItemToObject

将 item 任意类型的 cJSON 结构体(字符串、数字、对象、数组等)。作为键 string 的值添加到 object 中。

cJSON_AddItemToObjectCS

与 cJSON_AddItemToObject 类似,但这个函数假设 string 是常量且其生命周期至少与 item 一样长。这意味着 string 字符串不会被 cJSON 库复制,而是直接引用。

cJSON_AddItemReferenceToObject

将 item 的引用作为键 string 的值添加到 object 中。与 cJSON_AddItemToObject 不同的是,这里不复制 item,而是直接引用它。

cJSON_AddItemToObject嵌套对象的简单使用例

代码语言:cpp
复制
	// 创建 JSON 数据
	cJSON* json = cJSON_CreateObject();
	cJSON_AddStringToObject(json, "name", "Yzc");
	cJSON_AddNumberToObject(json, "age", 18);
    //创造嵌套对象
	cJSON* address = cJSON_CreateObject();
	cJSON_AddStringToObject(address, "street", "changsha");
	cJSON_AddNumberToObject(address, "zip", 10086);
	//嵌套对象将address赋给json
	cJSON_AddItemToObject(json, "address", address);

使用宏定义添加数据的简单使用例:

代码语言:cpp
复制
	cJSON* root = cJSON_CreateObject();
	const char* maxNumber = "18";
	cJSON_AddStringToObject(root, "maxNumber", maxNumber);
	cJSON_AddNumberToObject(root, "result", 1);
	cJSON_AddNullToObject(root, "nullValue");
	cJSON_AddTrueToObject(root, "isActive");
	cJSON_AddFalseToObject(root, "isInactive");
	cJSON_AddBoolToObject(root, "isEnabled", true);
	char* rootShow = cJSON_Print(root);

获取/解析 JSON 数据

获取JSON数据相关

代码语言:cpp
复制
/* Get Array size/item / object item. */
int    cJSON_GetArraySize(cJSON *array)							
{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
cJSON *cJSON_GetArrayItem(cJSON *array,int item)				
{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	
{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}

cJSON_GetObjectItem

返回 object 中键名为 string 的元素。

cJSON_GetObjectItem相关使用例

注意:cJSON_GetObjectItem(root, "number")->valuestring返回的实际上是char* 类型

假设root里有 key 为 Id rootName number 的键值对

代码语言:cpp
复制
    cJSON* root = cJSON_CreateObject():
	int Id = cJSON_GetObjectItem(root, "Id")->valueint;
	const char* rootName = cJSON_GetObjectItem(root, "rootName")->valuestring;
    cJSON* cJSONNumberTest = cJSON_GetObjectItem(root, "number")
    int number = cJSONNumberTest ->valueint;
    std::string str1111(cJSON_GetObjectItem(root, "number")->valuestring);

cJSON_GetArrayItem

返回 array 中位于索引 item 的元素。

cJSON_GetArraySize

计算并返回 array 中的元素个数。

遍历 JSON 数据的一个简单示例

注意 :这里的alphabet 是cJSON_Array类型

代码语言:cpp
复制
	if (alphabet->type == cJSON_Array) {
		int arraySize = cJSON_GetArraySize(alphabet);
		for (int i = 0; i < arraySize; i++) {
			cJSON* item = cJSON_GetArrayItem(alphabet, i);
			if (item->type == cJSON_String) {
				std::cout << "Element " << i << ": " << item->valuestring << std::endl;
			}
		}
	}

解析相关

cJSON cJSON_Parse(const char value) 从字符串中解析 JSON 数据。

一个简单的使用例

代码语言:cpp
复制
	// 创建 JSON 数据
	cJSON* json = cJSON_CreateObject();
    //~~~略过相应的数据创造和解析相关,参考简单的使用例即可
	// 解析 JSON 数据
	cJSON* parsed_json = cJSON_Parse(json_string);

cJSON cJSON_ParseWithOpts(const char value, size_t length, int require_null_terminated)

cJSON_ParseWithOpts的解析及其简单使用例:

value:指向待解析 JSON 字符串的常量指针。

return_parse_end: 指向一个 const char * 的指针。如果非 NULL,函数会将解析结束位置的指针存储在这里。这有助于调试和验证解析是否成功到达了字符串的末尾。

require_null_terminated: 一个布尔值(实际上是一个整数),用来指示是否要求 JSON 字符串以空字符 (\0) 终止。如果设置为 1,则要求字符串以 \0 结尾;如果设置为 0,则不作此要求。

返回值

如果成功解析 JSON 字符串,返回指向 cJSON 结构体的指针。

如果解析失败,返回 NULL。可以通过 cJSON_GetErrorPtr() 获取失败原因。

代码语言:cpp
复制
    // 创建 JSON 字符串
    const char *json_string = "{\"name\":\"John\",\"age\":30}";

    // 解析 JSON 数据
    const char *end_of_parsed;
    cJSON *parsed_json = cJSON_ParseWithOpts(json_string, &end_of_parsed, 1);

    if (parsed_json) {
        // 解析成功
        printf("Parsed successfully.\n");
        printf("End of parsing: '%s'\n", end_of_parsed);

        // 获取 "name" 键的值
        cJSON *name_item = cJSON_GetObjectItem(parsed_json, "name");
        if (name_item && name_item->type == cJSON_String) {
            printf("Name: %s\n", name_item->valuestring);
        }

        // 获取 "age" 键的值
        cJSON *age_item = cJSON_GetObjectItem(parsed_json, "age");
        if (age_item && age_item->type == cJSON_Number) {
            printf("Age: %d\n", age_item->valueint);
        }

        // 清理 JSON 数据
        cJSON_Delete(parsed_json);
    } else {
        // 解析失败
        printf("Failed to parse JSON data: %s\n", cJSON_GetErrorPtr());
    }

获取 JSON 数据类型

这里的json 是cJSON* 类型

int jsonType = json->type;

对应的jsonType

代码语言:cpp
复制
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6

转换 JSON 数据(CS交互常用)

char *cJSON_Print(cJSON *value): 将 JSON 数据转换为字符串(默认格式化输出)。

char *cJSON_PrintUnformatted(cJSON *value): 将 JSON 数据转换为字符串(不格式化输出)。

释放内存

void cJSON_Delete(cJSON *c): 删除 JSON 对象及其所有子项,并释放关联的内存。

和在一起的一个cJSONapi相关简单使用例

代码语言:cpp
复制
#include <iostream>
#include "cJSON.h"

int main() {
	// 创建 JSON 数据
	cJSON* JsonTest = cJSON_CreateObject();
	cJSON_AddStringToObject(JsonTest, "name", "Yzc");
	cJSON_AddNumberToObject(JsonTest, "age", 18);
	//嵌套对象cJSON
	cJSON* address = cJSON_CreateObject();
	cJSON_AddStringToObject(address, "street", "changsha");
	cJSON_AddNumberToObject(address, "zip", 10086);
	cJSON_AddItemToObject(JsonTest, "address", address);

	// 打印 JSON 数据
	std::string json_string(cJSON_Print(JsonTest));
	std::cout << "JSON Data:\n" << json_string << std::endl;
	// 解析 JSON 数据示例
	cJSON* parsed_json = cJSON_Parse(json_string.c_str());
	if (parsed_json) {
		// 获取 "name" 键的值
		cJSON* name_item = cJSON_GetObjectItem(parsed_json, "name");
		//std::string abc = name_item->valuestring;
		//std::cout << "abc:" << abc << std::endl;
		if (name_item && name_item->type == cJSON_String) {
			std::cout << "Name:" << name_item->valuestring << std::endl;
		}

		// 获取 "age" 键的值
		cJSON* age_item = cJSON_GetObjectItem(parsed_json, "age");
		if (age_item && age_item->type == cJSON_Number) {
			std::cout << "Age:" << age_item->valueint << std::endl;
		}

		// 嵌套对象示例
		cJSON* address_item = cJSON_GetObjectItem(parsed_json, "address");
		if (address_item && address_item->type == cJSON_Object) {
			cJSON* street_item = cJSON_GetObjectItem(address_item, "street");
			if (street_item && street_item->type == cJSON_String) {
				std::cout << "Street:" << street_item->valuestring << std::endl;
			}
			cJSON* zip_item = cJSON_GetObjectItem(address_item, "zip");
			if (zip_item && zip_item->type == cJSON_Number) {
				std::cout << "Zip:" << zip_item->valueint << std::endl;
			}
		}

		// 清理 解析的JSON 数据
		cJSON_Delete(parsed_json);
	}
	else {
		// 解析失败时的错误处理
		std::cout <<"Failed to parse JSON data: %s\n\n" << cJSON_GetErrorPtr() << std::endl;
	}
	//非格式化输出
	std::string cJSON_Show(cJSON_PrintUnformatted(JsonTest));

	std::cout << "\ncJSON_Show:" << cJSON_Show << std::endl;

	cJSON* alphabet = cJSON_CreateArray();

	cJSON_AddItemToArray(alphabet, cJSON_CreateString("A"));
	cJSON_AddItemToArray(alphabet, cJSON_CreateString("B"));
	cJSON_AddItemToArray(alphabet, cJSON_CreateString("C"));

	if (alphabet->type == cJSON_Array) {
		int arraySize = cJSON_GetArraySize(alphabet);
		for (int i = 0; i < arraySize; i++) {
			cJSON* item = cJSON_GetArrayItem(alphabet, i);
			if (item->type == cJSON_String) {
				std::cout << "Element " << i << ": " << item->valuestring << std::endl;
			}
		}
	}
	const char* strAlphabet =cJSON_Print(alphabet);

	std::cout << "\nstrAlphabet:" << strAlphabet << std::endl;

    //添加数据示例
	cJSON* root = cJSON_CreateObject();
	const char* maxNumber = "18";

	cJSON_AddStringToObject(root, "maxNumber", maxNumber);
	cJSON_AddNumberToObject(root, "result", 1);
	cJSON_AddNullToObject(root, "nullValue");
	cJSON_AddTrueToObject(root, "isActive");
	cJSON_AddFalseToObject(root, "isInactive");
	cJSON_AddBoolToObject(root, "isEnabled", true);
	std::string rootShow(cJSON_Print(root));

	std::cout << "\nrootShow:" << rootShow << std::endl;

	// 清理
	cJSON_Delete(JsonTest);
	//cJSON_Delete(address);
	//address 是嵌套在 JsonTest 上的
	//之所以不需要这个Delete了 是因为cJSON_Delete(JsonTest)会把所有衍伸得cJSON对象都删除
	cJSON_Delete(alphabet);
	cJSON_Delete(root);

	return 0;
}

运行截图:

CS数据传输以一个简单的注册信息交互为例

略去服务端客户端的搭建,这里仅以数据交互为例

发送或接收时:

首先声明一个cJSON* 的root对象用于存储信息

将内容通过键值对的方式绑定到root对象以后

将其转换字符串,格式化或者非格式化都行,非格式化会节约字符串内存,格式化易于阅读

然后通过CS交互的信息传递如recv或者send函数进行交互

最后记得删除cJSON* 对象

客户端

发送注册消息

代码语言:cpp
复制
void SendRegisterRequest(const char* nickname,const char* password)
{
	cJSON* root = cJSON_CreateObject();
	cJSON_AddStringToObject(root, "cmd", "CS_Register");
	cJSON_AddStringToObject(root, "nickname", nickname);
	cJSON_AddStringToObject(root, "password", password);

	char* data = cJSON_PrintUnformatted(root);
	int len = strlen(data);

	send(sockClient, data, len, 0);

	cJSON_Delete(root);
	free(data);
}

接收注册信息

代码语言:cpp
复制
int GameClient::OnNetMsg(const char* buf, int len)
{
	std::string msg(buf, len);
	printf("Client recv<-----%s\n", msg.c_str());

	cJSON* root = cJSON_Parse(data);

	if (root == nullptr) return size;

	cJSON* cmd = cJSON_GetObjectItem(root, "cmd");

	if (strcmp("SC_Register", cmd->valuestring) == 0)
	{
		cJSON* msg = cJSON_GetObjectItem(root, "msg");
		if (strcmp(msg->valuestring, "Register Success") == 0)
		{
			std::cout << "Register successful!" << std::endl;
			CS_RegisterEvent(root);
		}
		else std::cout << "Client Register Failed,User isExitence" << std::endl;
	}
	else {
		printf("未知命令 [%s]\n", cmd->valuestring);
	}

	cJSON_Delete(root);
	return size;
}

服务端

接收注册请求消息

代码语言:cpp
复制
int TcpSocket::OnNetMsg(const char* buf, int len)
{
	std::string msg(buf , size);

	printf("Server recv<-----%s\n", msg.c_str());

	cJSON* root = cJSON_Parse(msg.c_str());

	cJSON* cmd = cJSON_GetObjectItem(root, "cmd");

	if (cmd == nullptr)
	{
		cJSON_Delete(root);
		return size;
	}

	if (cmd->type != cJSON_String)
	{
		Close();
		cJSON_Delete(root);
		return size;
	}
	if (strcmp("CS_Register", cmd->valuestring) == 0)
		SC_RegisterRespond(root);
	else
		Close();

	cJSON_Delete(root);
	return size;
}

发送注册回复消息

代码语言:cpp
复制
void TcpSocket::SC_RegisterRespond(cJSON* root)
{
	cJSON* nickname = cJSON_GetObjectItem(root, "nickname");
	cJSON* password = cJSON_GetObjectItem(root, "password");

	if (nickname == nullptr || nickname->type != cJSON_String)
	{
		Close();
		return;
	}

	cJSON* sc_register = cJSON_CreateObject();

	// 随机生成 不重复8位字符串
	std::string uniqueString = generateUniqueRandomString(8);
	std::cout << "Generated unique random string: " << uniqueString << std::endl;

	cJSON_AddStringToObject(sc_register, "cmd", "SC_Register");
	cJSON_AddStringToObject(sc_register, "token", uniqueString.c_str());
	cJSON_AddStringToObject(sc_register, "nickname", nickname->valuestring);
	cJSON_AddStringToObject(sc_register, "password", password->valuestring);
	cJSON_AddNumberToObject(sc_register, "result", 1);
	cJSON_AddStringToObject(sc_register, "msg", "Register Success");
	}

	char* msg = cJSON_Print(sc_register);

	cJSON_Delete(sc_register);

	SendData(msg, strlen(msg));

	free(msg);

}

截图展示

总结

JSON 格式简单明了,易于理解和编写,而且api调用简单易于理解和阅读。

数据传输格式用JSON,日志里的数据交互阅读起来简单舒服得多。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • cJSON简介:一种高效且易于使用的 JSON 解析器和生成器
  • cJSON介绍:
    • 创建 JSON 数据:
      • 添加数据
        • AddItemToArray使用例子
        • cJSON_AddItemToObject嵌套对象的简单使用例
        • 使用宏定义添加数据的简单使用例:
      • 获取/解析 JSON 数据
        • 获取JSON数据相关
        • cJSON_GetObjectItem相关使用例
        • 遍历 JSON 数据的一个简单示例
        • 解析相关
        • 一个简单的使用例
        • cJSON_ParseWithOpts的解析及其简单使用例:
      • 获取 JSON 数据类型
        • 转换 JSON 数据(CS交互常用)
          • 释放内存
          • 和在一起的一个cJSONapi相关简单使用例
          • CS数据传输以一个简单的注册信息交互为例
            • 客户端
              • 发送注册消息
              • 接收注册信息
            • 服务端
              • 接收注册请求消息
              • 发送注册回复消息
            • 截图展示
            • 总结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档