欧易下载
欧易交易所
<欧易官方
欧易app
欧易下载
欧易交易所
欧易官方
欧易app
chrome浏览器
谷歌浏览器
快连下载
快连下载
快连下载
chrome浏览器
谷歌浏览器
快连下载
快连下载
快连下载
快连
快连
快连
快连下载
whatsapp网页版
whatsapp网页版
whatsapp网页版
whatsapp网页版
快连
快连
快连下载
whatsapp网页版
whatsapp网页版
whatsapp网页版
whatsapp网页版
C语言中JSON通讯的实现方法与实践
在跨平台、跨语言的系统开发中,JSON(JavaScript Object Notation)因其轻量级、易读性强、解析效率高的特点,已成为数据交换的主流格式之一,C语言作为系统级编程的基础语言,常用于后端服务、嵌入式开发等场景,实现JSON格式的数据通讯是许多项目的核心需求,本文将详细介绍C语言中JSON通讯的实现原理、关键步骤及常用工具,并通过代码示例展示完整流程。
JSON通讯的核心原理
JSON通讯的本质是数据的序列化(编码)与反序列化(解码):
- 序列化:将C语言中的数据结构(如结构体、数组、基本类型)转换为JSON格式的字符串,便于网络传输或存储。
- 反序列化:将接收到的JSON字符串解析为C语言可识别的数据结构,供程序逻辑处理。
完整的JSON通讯流程通常包括:
- 数据封装:在发送端,将业务数据按JSON格式序列化为字符串;
- 数据传输:通过TCP/IP、HTTP、WebSocket等协议传输JSON字符串;
- 数据解析:在接收端,解析JSON字符串并还原为原始数据结构;
- 业务处理:基于解析后的数据进行后续逻辑操作。
选择合适的JSON库
C语言没有内置JSON支持,需依赖第三方库实现序列化与反序列化,以下是几款主流的JSON库及其特点:
cJSON
- 特点:轻量级、单文件实现(仅
cJSON.h和cJSON.c)、API简单、无需依赖其他库。 - 适用场景:对资源占用敏感的嵌入式系统或小型项目。
- GitHub地址:https://github.com/DaveGamble/cJSON
Jansson
- 特点:功能完善(支持JSON标准全类型)、内存管理自动化、性能较好。
- 适用场景:中大型项目,需要稳定性和高级功能(如JSON路径查询)。
- 官网:https://github.com/akheron/jansson
Parson
- 特点:轻量级、跨平台、API设计直观,支持流式解析(适合大JSON文件)。
- 适用场景:需要平衡性能与易用性的项目。
- GitHub地址:https://github.com/kgabis/parson
本文以cJSON为例,因其“开箱即用”的特性,适合初学者快速理解JSON通讯的实现。
基于cJSON的JSON通讯实现步骤
环境准备
下载cJSON源码(或通过包管理器安装,如apt-get install libcjson-dev),将cJSON.h和cJSON.c添加到项目中,编译时链接cJSON库:
gcc -o app app.c cJSON.c -lm
数据序列化:将C数据转为JSON字符串
假设需要发送一个用户信息数据,包含用户ID、姓名、年龄和爱好列表,定义C结构体如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
typedef struct {
int id;
char name[50];
int age;
char *hobbies[3]; // 动态数组存储爱好
} UserInfo;
通过cJSON的API构建JSON对象并序列化:
char* serializeUserInfo(const UserInfo *user) {
// 1. 创建JSON对象(对应JSON的{})
cJSON *root = cJSON_CreateObject();
if (!root) {
fprintf(stderr, "Failed to create JSON object\n");
return NULL;
}
// 2. 添加键值对(cJSON_AddNumber/String/Array等)
cJSON_AddNumberToObject(root, "id", user->id);
cJSON_AddStringToObject(root, "name", user->name);
cJSON_AddNumberToObject(root, "age", user->age);
// 3. 添加爱好数组(对应JSON的[])
cJSON *hobbiesArray = cJSON_CreateArray();
for (int i = 0; i < 3; i++) {
if (user->hobbies[i] != NULL) {
cJSON_AddItemToArray(hobbiesArray, cJSON_CreateString(user->hobbies[i]));
}
}
cJSON_AddItemToObject(root, "hobbies", hobbiesArray);
// 4. 序列化为字符串(需手动释放)
char *jsonStr = cJSON_Print(root);
if (!jsonStr) {
fprintf(stderr, "Failed to serialize JSON\n");
cJSON_Delete(root);
return NULL;
}
// 5. 释放JSON对象(避免内存泄漏)
cJSON_Delete(root);
return jsonStr;
}
调用示例:
int main() {
UserInfo user = {
.id = 1001,
.name = "Alice",
.age = 25,
.hobbies = {"reading", "swimming", "coding"}
};
char *jsonStr = serializeUserInfo(&user);
if (jsonStr) {
printf("Serialized JSON: %s\n", jsonStr);
free(jsonStr); // 释放序列化字符串
}
return 0;
}
输出结果:
{"id":1001,"name":"Alice","age":25,"hobbies":["reading","swimming","coding"]}
数据反序列化:将JSON字符串转为C数据
假设接收端收到上述JSON字符串,需解析为UserInfo结构体:
int deserializeUserInfo(const char *jsonStr, UserInfo *user) {
// 1. 解析JSON字符串
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
fprintf(stderr, "Failed to parse JSON: %s\n", cJSON_GetErrorPtr());
return -1;
}
// 2. 获取键值对(cJSON_GetObjectItem等)
cJSON *idItem = cJSON_GetObjectItem(root, "id");
cJSON *nameItem = cJSON_GetObjectItem(root, "name");
cJSON *ageItem = cJSON_GetObjectItem(root, "age");
cJSON *hobbiesArray = cJSON_GetObjectItem(root, "hobbies");
if (!idItem || !nameItem || !ageItem || !hobbiesArray) {
fprintf(stderr, "Missing required fields in JSON\n");
cJSON_Delete(root);
return -1;
}
// 3. 填充C结构体
user->id = idItem->valueint;
strncpy(user->name, nameItem->valuestring, sizeof(user->name) - 1);
user->age = ageItem->valueint;
// 4. 解析数组
int hobbyCount = cJSON_GetArraySize(hobbiesArray);
for (int i = 0; i < hobbyCount && i < 3; i++) {
cJSON *hobbyItem = cJSON_GetArrayItem(hobbiesArray, i);
if (hobbyItem && hobbyItem->valuestring) {
user->hobbies[i] = strdup(hobbyItem->valuestring); // 需手动释放
}
}
// 5. 释放JSON对象
cJSON_Delete(root);
return 0;
}
调用示例:
int main() {
const char *jsonStr = "{\"id\":1001,\"name\":\"Alice\",\"age\":25,\"hobbies\":[\"reading\",\"swimming\",\"coding\"]}";
UserInfo user;
if (deserializeUserInfo(jsonStr, &user) == 0) {
printf("Deserialized UserInfo:\n");
printf("ID: %d\n", user.id);
printf("Name: %s\n", user.name);
printf("Age: %d\n", user.age);
printf("Hobbies: %s, %s, %s\n", user.hobbies[0], user.hobbies[1], user.hobbies[2]);
// 释放动态分配的字符串
for (int i = 0; i < 3; i++) {
if (user.hobbies[i]) free(user.hobbies[i]);
}
}
return 0;
}
网络传输:基于TCP的JSON通讯
JSON字符串本身是文本格式,可直接通过TCP套接字传输,以下是简单的客户端-服务器通讯示例:
服务器端(接收并解析JSON)
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
// 1. 创建socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 2. 绑定端口
if (setsockopt(server


还没有评论,来说两句吧...