范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

例说嵌入式实用知识之JSON数据

  前言
  JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。JSON在互联网相关开发中用得很多,在我们嵌入式中用得也不少。最近在项目中就有用到,用起来很方便。
  简单的JSON格式数据如:{     "name": "xxx",     "num": xxx,     "c_score": xxx }
  这里我们需要知道一个概念:键值对 。比如:"name": "xxx"
  像这样子的就是一对键值对。
  当我们作为发送方时,我们要把xxx这些有用的数据组合成JSON格式的数据发送给接收方;当我们作为接收方时,我们需要从这一堆JSON数据中解析出xxx这些有用的数据拿来使用。简单的JSON数据,我们使用C语言的一些字符串操作相关的库函数也是可以做到组包和解析的,但是一些稍微复杂一点的JSON,可能就没那么好操作了。
  这时候我们可以借助一个第三方库——cJSON库 ,可以很方便来做数据组包及解析。
  cJSON库仓库地址:
  https://github.com/DaveGamble/cJSON.git
  或者
  https://gitee.com/mirrors/cJSON.git
  下面我们通过实例来分享使用cJSON库来做数据组包及数据解析。组包、解析示例1、确定协议数据
  在实际开发中,要把JSON数据作为通信的数据,自然要先确定通信双方要交互的数据有哪些,如有需要还需编写形成协议文档。协议文档包含要传输的数据,数据类型等信息。比如:
  2、组JSON数据包示例
  从控制台输入一些学生信息,组合成字符串格式的JSON数据包,然后再输出至控制台。操作示例:
  首先,我们先从仓库下载cJSON 源码,文件夹内容如:
  我们只需要把cJSON.c 、cJSON.h 两个文件复制到我们工程的根目录下就可以使用,如:
  从cJSON.h 可以看到其给我们提供了很多接口:
  本例中我们重点关注如下几个接口即可:cJSON_CreateObject:创建JSON对象,{}扩起来的 cJSON_CreateString:创建字符串 cJSON_CreateNumber:创建int类型数据 cJSON_AddItemToObject:添加到JSON对象中 cJSON_Print:呈现为标准的JSON格式 cJSON_PrintUnformatted:呈现为去掉空格的JSON格式 cJSON_Delete:JSON对象删除,做一些释放内存的工作
  我们创建的的组包函数如下:static char *StudentsData_Packet(pStudentDef _Stu) {     char *res_string = NULL;    // 返回值     cJSON *name = NULL;         // 名字     cJSON *num = NULL;          // 学号     cJSON *c_score = NULL;      // C语言分数      /* 创建一个JSON对象,{}扩起来 */     cJSON *obj = cJSON_CreateObject();     if (obj == NULL)     {         goto end;     }      /* 创建 "name": "xxx" 键值对 */     name = cJSON_CreateString(_Stu->name);     if (name == NULL)     {         goto end;     }     cJSON_AddItemToObject(obj, "name", name);      /* 创建 "num": 207 键值对 */     num = cJSON_CreateNumber(_Stu->num);     if (name == NULL)     {         goto end;     }     cJSON_AddItemToObject(obj, "num", num);          /* 创建 "c_score": 95 键值对 */     c_score = cJSON_CreateNumber(_Stu->c_score);     if (name == NULL)     {         goto end;     }     cJSON_AddItemToObject(obj, "c_score", c_score);       res_string = cJSON_Print(obj);          // 呈现为JSON格式      // res_string = cJSON_PrintUnformatted(obj);   // 呈现为无格式      if (res_string == NULL)     {         fprintf(stderr, "Failed to print monitor. ");     }  /* 异常情况统一Delete(free) */ end:     cJSON_Delete(obj);     return res_string; }
  详细解释见注释。我们重点看一下cJSON_Print 与cJSON_PrintUnformatted 这两个接口。这两个接口的差别就是组合成的JSON数据是否有空格。我们通过JSON相关的在线网站看一下其区别:
  https://www.sojson.com/json/json_online.html
  有空格的JSON数据,即用cJSON_Print 时的效果为:
  无空格的JSON数据,即用cJSON_PrintUnformatted 时的效果为:
  如果想要输出查看时,当然是用cJSON_Print 比较方便查看;如果是实际通信时,当然是用cJSON_PrintUnformatted 会比较好,毕竟去掉空格就可以减小一定程度的通信负担。
  完整代码:/*     作者:ZhengN     公众号:嵌入式大杂烩 */  #include  #include  #include  #include "cJSON.h"  #define  STU_NAME_LEN  32  /* 学生结构体 */ typedef struct _Student {     char name[STU_NAME_LEN];  // 名字           int num;                  // 学号           int c_score;              // C语言分数 }StudentDef, *pStudentDef;  /* 内部函数声明 */ static char *StudentsData_Packet(pStudentDef _Stu);  /******************************************************************************************************** ** 函数: main **------------------------------------------------------------------------------------------------------ ** 参数:  ** 说明:  ** 返回:  ********************************************************************************************************/ int main(void) {     char name[STU_NAME_LEN] = {0};     int num = 0;     int c_score = 0;     StudentDef stu;     int stu_count = 0;     int i = 0;      /* 学生总人数 */     printf("Please input number of student: ");     scanf("%d", &stu_count);      while (i++ < stu_count)     {         /* 名字 */         printf("Please input name: ");         scanf("%s", name);         if (strlen(name) < STU_NAME_LEN)         {             strncpy((char*)&stu.name, name, strlen(name)+1);         }         else         {             printf("The name is too long ");         }                  /* 学号 */         printf("Please input num (0~100): ");         scanf("%d", &num);         stu.num = num;          /* C语言分数 */         printf("Please input c_score (0~100): ");         scanf("%d", &c_score);         stu.c_score = c_score;          /* 输出JSON格式的学生数据 */         printf("%s ", StudentsData_Packet(&stu));     }      return 0; }  /******************************************************************************************************** ** 函数: StudentsData_Packet, 学生JSON格式数据组包 **------------------------------------------------------------------------------------------------------ ** 参数: _Stu:组student json数据包需要的数据 ** 说明:  ** 返回: JSON格式的字符串    ********************************************************************************************************/ static char *StudentsData_Packet(pStudentDef _Stu) {     char *res_string = NULL;    // 返回值     cJSON *name = NULL;         // 名字     cJSON *num = NULL;          // 学号     cJSON *c_score = NULL;      // C语言分数      /* 创建一个JSON对象,{}扩起来 */     cJSON *obj = cJSON_CreateObject();     if (obj == NULL)     {         goto end;     }      /* 创建 "name": "xxx" 键值对 */     name = cJSON_CreateString(_Stu->name);     if (name == NULL)     {         goto end;     }     cJSON_AddItemToObject(obj, "name", name);      /* 创建 "num": 207 键值对 */     num = cJSON_CreateNumber(_Stu->num);     if (name == NULL)     {         goto end;     }     cJSON_AddItemToObject(obj, "num", num);          /* 创建 "c_score": 95 键值对 */     c_score = cJSON_CreateNumber(_Stu->c_score);     if (name == NULL)     {         goto end;     }     cJSON_AddItemToObject(obj, "c_score", c_score);       res_string = cJSON_Print(obj);          // 呈现为JSON格式      // res_string = cJSON_PrintUnformatted(obj);   // 呈现为无格式      if (res_string == NULL)     {         fprintf(stderr, "Failed to print monitor. ");     }  /* 异常情况统一Delete(free) */ end:     cJSON_Delete(obj);     return res_string; }3、解析JSON数据包示例
  我们把我们想要解析的数据放到一个student_data.txt 文件中,然后读取其内容拿来解析,最后输出解析结果。
  student_data.txt 的内容如:
  解析结果:
  关于这个示例我们需要关注的接口有:cJSON_Parse:JSON解析函数,解析{}得到里面的内容 cJSON_GetObjectItemCaseSensitive:从对象中获取键"字符串"。不分大小写 cJSON_IsString:判断是否是字符串 cJSON_IsNumber:判断是否是整形数 cJSON_Delete:JSON对象删除,做一些释放内存的工作
  我们创建的解析函数如下:static void StudentsData_Parse(pStudentDef _Stu, const char *_JsonStudnetData) {     cJSON *student_json = NULL;   // student_json操作对象,可代表 {} 扩起来的内容     cJSON *name = NULL;                  cJSON *num = NULL;     cJSON *c_score = NULL;          /* 开始解析 */     student_json = cJSON_Parse(_JsonStudnetData);     if (NULL == student_json)     {         const char *error_ptr = cJSON_GetErrorPtr();         if (error_ptr != NULL)         {             fprintf(stderr, "Error before: %s ", error_ptr);         }         goto end;     }      /* 解析获取name得值 */     name = cJSON_GetObjectItemCaseSensitive(student_json, "name");     if (cJSON_IsString(name) && (name->valuestring != NULL))     {         memcpy(&_Stu->name, name->valuestring, strlen(name->valuestring));     }      /* 解析获取num的值 */     num = cJSON_GetObjectItemCaseSensitive(student_json, "num");     if (cJSON_IsNumber(num))     {         _Stu->num = num->valueint;     }      /* 解析获取c_score的值 */     c_score = cJSON_GetObjectItemCaseSensitive(student_json, "c_score");     if (cJSON_IsNumber(c_score))     {         _Stu->c_score = c_score->valueint;     }  end:     cJSON_Delete(student_json); }
  解释见注释。
  完整代码:/*     作者:ZhengN     公众号:嵌入式大杂烩 */ #include  #include  #include  #include "cJSON.h"  #define  STU_NAME_LEN  32  /* 学生结构体 */ typedef struct _Student {     char name[STU_NAME_LEN];  // 名字           int num;                  // 学号           int c_score;              // C语言分数 }StudentDef, *pStudentDef;  /* 内部函数声明 */ static void StudentsData_Parse(pStudentDef _Stu, const char *_JsonStudnetData); static void PrintParseResult(const pStudentDef _Stu);  /******************************************************************************************************** ** 函数: main **------------------------------------------------------------------------------------------------------ ** 参数:  ** 说明:  ** 返回:  ********************************************************************************************************/ int main(void) {     StudentDef stu = {0};  // 保存解析后的数据     int file_len = 0;      // 文件长度     FILE *fp = NULL;       // 文件句柄     char *data = NULL;     // 用于保存从文件读出的数据      /* 文件操作 */     if ((fp = fopen("student_data.txt", "r")) == NULL)     {         printf("Open file error! ");         exit(EXIT_FAILURE);     }     fseek(fp, 0, SEEK_END);    // 文件位置指针指向文件末尾     file_len = ftell(fp);      // 获取文末相对于文首的偏移值     fseek(fp, 0, SEEK_SET);    // 文件位置指针指向文首     data = (char*)malloc(file_len+1); // 为data申请堆内存     fread(data,file_len,1,fp); // 读取文件数据保存至data     fclose(fp);                // 关闭文件      /* 解析 */     StudentsData_Parse(&stu, (const char*)data);        /* 打印输出解析结果 */     PrintParseResult(&stu);        /* 释放内存 */      free(data);   // 防止内存泄漏     data = NULL;  // 防止出现野指针      return 0; }  /******************************************************************************************************** ** 函数: StudentsData_Parse, JOSN格式学生期末数据解析 **------------------------------------------------------------------------------------------------------ ** 参数: _JsonStudnetData:JSON数据   _Stu:保存解析出的有用数据 ** 说明:  ** 返回:  ********************************************************************************************************/ static void StudentsData_Parse(pStudentDef _Stu, const char *_JsonStudnetData) {     cJSON *student_json = NULL;   // student_json操作对象,可代表 {} 扩起来的内容     cJSON *name = NULL;                  cJSON *num = NULL;     cJSON *c_score = NULL;          /* 开始解析 */     student_json = cJSON_Parse(_JsonStudnetData);     if (NULL == student_json)     {         const char *error_ptr = cJSON_GetErrorPtr();         if (error_ptr != NULL)         {             fprintf(stderr, "Error before: %s ", error_ptr);         }         goto end;     }      /* 解析获取name得值 */     name = cJSON_GetObjectItemCaseSensitive(student_json, "name");     if (cJSON_IsString(name) && (name->valuestring != NULL))     {         memcpy(&_Stu->name, name->valuestring, strlen(name->valuestring));     }      /* 解析获取num的值 */     num = cJSON_GetObjectItemCaseSensitive(student_json, "num");     if (cJSON_IsNumber(num))     {         _Stu->num = num->valueint;     }      /* 解析获取c_score的值 */     c_score = cJSON_GetObjectItemCaseSensitive(student_json, "c_score");     if (cJSON_IsNumber(c_score))     {         _Stu->c_score = c_score->valueint;     }  end:     cJSON_Delete(student_json); }  /******************************************************************************************************** ** 函数: PrintParseResult, 打印输出解析结果 **------------------------------------------------------------------------------------------------------ ** 参数:  ** 说明:  ** 返回:  ********************************************************************************************************/ static void PrintParseResult(const pStudentDef _Stu) {     printf("name: %s, num: %d, c_score: %d ", _Stu->name, _Stu->num, _Stu->c_score); }综合示例
  上一节中我们的组包、解析demo都是分开测试的,这一节再分享一个两个demo综合起来的demo:
  运行演示:
  json_print.c完整代码:/*     作者:ZhengN     公众号:嵌入式大杂烩 */ #include  #include  #include  #include  #include "cJSON.h"  #define  STU_NAME_LEN  32  /* 学生结构体 */ typedef struct _Student {     char name[STU_NAME_LEN];  // 名字           int num;                  // 学号           int c_score;              // C语言分数 }StudentDef, *pStudentDef;  /* 内部函数声明 */ static StudentDef StudentData_Prepare(void); static char *StudentsData_Packet(pStudentDef _Stu); static void StudentData_Send(const char *_data);  /******************************************************************************************************** ** 函数: main **------------------------------------------------------------------------------------------------------ ** 参数:  ** 说明:  ** 返回:  ********************************************************************************************************/ int main(void) {     StudentDef stu = {0};     char *stu_data = NULL;     int stu_count = 0;     int i = 0;      /* 需要登记的学生总人数 */     printf("Please input number of student: ");     scanf("%d", &stu_count);      while (i++ < stu_count)     {         /* 准备数据 */         stu = StudentData_Prepare();          /* JSON格式数据组包 */         stu_data = StudentsData_Packet(&stu);          /* 发送数据 */         StudentData_Send(stu_data);     }      return 0; }  /******************************************************************************************************** ** 函数: StudentData_Prepare, 准备组包需要的数据 **------------------------------------------------------------------------------------------------------ ** 参数:  ** 说明:  ** 返回: 获取得到的数据 ********************************************************************************************************/ static StudentDef StudentData_Prepare(void) {     char name[STU_NAME_LEN] = {0};     int num = 0;     int c_score = 0;     StudentDef stu;      /* 名字 */     printf("Please input name: ");     scanf("%s", name);     if (strlen(name) < STU_NAME_LEN)     {         strncpy((char*)&stu.name, name, strlen(name)+1);     }     else     {         printf("The name is too long ");     }          /* 学号 */     printf("Please input num (0~100): ");     scanf("%d", &num);     stu.num = num;      /* C语言分数 */     printf("Please input c_score (0~100): ");     scanf("%d", &c_score);     stu.c_score = c_score;      return stu; }  /******************************************************************************************************** ** 函数: StudentsData_Packet, JSON格式数据组包 **------------------------------------------------------------------------------------------------------ ** 参数: _Stu:组student json数据包需要的数据 ** 说明:  ** 返回: JSON格式的字符串	 ********************************************************************************************************/ static char *StudentsData_Packet(pStudentDef _Stu) {     char *res_string = NULL;    // 返回值     cJSON *name = NULL;         // 名字     cJSON *num = NULL;          // 学号     cJSON *c_score = NULL;      // C语言分数      /* 创建一个JSON对象,{}扩起来 */     cJSON *obj = cJSON_CreateObject();     if (obj == NULL)     {         goto end;     }      /* 创建 "name": "xxx" 键值对 */     name = cJSON_CreateString(_Stu->name);     if (name == NULL)     {         goto end;     }     cJSON_AddItemToObject(obj, "name", name);      /* 创建 "num": 207 键值对 */     num = cJSON_CreateNumber(_Stu->num);     if (name == NULL)     {         goto end;     }     cJSON_AddItemToObject(obj, "num", num);          /* 创建 "c_score": 95 键值对 */     c_score = cJSON_CreateNumber(_Stu->c_score);     if (name == NULL)     {         goto end;     }     cJSON_AddItemToObject(obj, "c_score", c_score);       res_string = cJSON_Print(obj);          // 呈现为JSON格式      // res_string = cJSON_PrintUnformatted(obj);   // 呈现为无格式      if (res_string == NULL)     {         fprintf(stderr, "Failed to print monitor. ");     }  /* 异常情况统一Delete(free) */ end:     cJSON_Delete(obj);     return res_string; }  /******************************************************************************************************** ** 函数: StudentData_Send, JSON格式字符串数据组包发送 **------------------------------------------------------------------------------------------------------ ** 参数: _data:要发送的数据 ** 说明:  ** 返回:  ********************************************************************************************************/ static void StudentData_Send(const char *_data) {     WSADATA wd; 	SOCKET ClientSock; 	SOCKADDR_IN  ServerSockAddr;      printf("%s  ", _data); 	 	/* 初始化操作sock需要的DLL */ 	WSAStartup(MAKEWORD(2,2),&wd);   	 	/* 向服务端发起请求 */     memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));       ServerSockAddr.sin_family = AF_INET;     ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");     ServerSockAddr.sin_port = htons(1314); 	     /* 创建客户端socket */     if (-1 == (ClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))     {         printf("socket error! ");         exit(EXIT_FAILURE);     }     if (-1 == connect(ClientSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR)))     {         printf("connect error! ");         exit(EXIT_FAILURE);     }      /* 发送数据到服务端 */     send(ClientSock, _data, strlen(_data), 0);          /* 关闭套接字 */     closesocket(ClientSock);    }json_parse.c完整代码:/*     作者:ZhengN     公众号:嵌入式大杂烩 */ #include  #include  #include  #include  #include "cJSON.h"  #define  STU_NAME_LEN  32  /* 学生结构体 */ typedef struct _Student {     char name[STU_NAME_LEN];  // 名字           int num;                  // 学号           int c_score;              // C语言分数 }StudentDef, *pStudentDef;  /* 内部函数声明 */ static char *StudentsData_Recv(void); static void StudentsData_Parse(pStudentDef _Stu, const char *_JsonStudnetData); static void PrintParseResult(const pStudentDef _Stu); static void SaveParseResult(const pStudentDef _Stu);  /* 内部全局变量 */ static FILE *stu_fp = NULL;  /******************************************************************************************************** ** 函数: main **------------------------------------------------------------------------------------------------------ ** 参数:  ** 说明:  ** 返回:  ********************************************************************************************************/ int main(void) {     StudentDef stu = {0};        char *recv_data;               while (1)     {         /* 接收数据 */         recv_data = StudentsData_Recv();          /* 解析 */         StudentsData_Parse(&stu, (const char*)recv_data);            /* 打印输出解析结果 */         PrintParseResult(&stu);            /* 保存数据到文件 */         SaveParseResult(&stu);       }      return 0; }  /******************************************************************************************************** ** 函数: StudentsData_Recv, 接收数据 **------------------------------------------------------------------------------------------------------ ** 参数:  ** 说明:  ** 返回:  ********************************************************************************************************/ static char *StudentsData_Recv(void) {     WSADATA wd; 	SOCKADDR_IN ServerSockAddr;     int recv_len = 0;     char *recv_buf = (char*)malloc(512);     static SOCKET ServerSock, ClientSock;     static SOCKADDR ClientAddr;     static int addr_size = 0;     static int run_count = 0;      /* 以下操作执行只一次就可以 */     if (0 == run_count)     {        /* 初始化操作sock需要的DLL */         WSAStartup(MAKEWORD(2,2),&wd);                    /* 创建服务端socket */         if (-1 == (ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))         {             printf("server socket error! ");             exit(EXIT_FAILURE);         }                  /* 设置服务端信息 */         memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); 	// 给结构体ServerSockAddr清零         ServerSockAddr.sin_family = AF_INET;  					// 使用IPv4地址         ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 本机IP地址         ServerSockAddr.sin_port = htons(1314);  				// 端口          /* 绑定套接字 */         if (-1 == bind(ServerSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR)))         {             printf("bind error! ");             exit(EXIT_FAILURE);         }          printf("bind ok! ");	         /* 进入监听状态 */         if (-1 == listen(ServerSock, 10))         {             printf("listen error! ");             exit(EXIT_FAILURE);         }         printf("listen ok! ");          addr_size = sizeof(SOCKADDR);     }              run_count++;      /* 监听客户端请求,accept函数返回一个新的套接字,发送和接收都是用这个套接字 */     if (-1 == (ClientSock = accept(ServerSock, (SOCKADDR*)&ClientAddr, &addr_size)))     {         printf("client socket error! ");         exit(EXIT_FAILURE);     }      /* 接受客户端的返回数据 */     memset(recv_buf, 0, 512);     recv_len = recv(ClientSock, recv_buf, 512, 0);     printf("%s ", recv_buf);          /* 关闭客户端套接字 */     closesocket(ClientSock);      /* 返回获取得到JSON数据 */     return (char*)recv_buf; }  /******************************************************************************************************** ** 函数: StudentsData_Parse, JOSN格式学生期末数据解析 **------------------------------------------------------------------------------------------------------ ** 参数: _JsonStudnetData:JSON数据   _Stu:保存解析出的有用数据 ** 说明:  ** 返回:  ********************************************************************************************************/ static void StudentsData_Parse(pStudentDef _Stu, const char *_JsonStudnetData) {     cJSON *student_json = NULL;   // student_json操作对象,可代表 {} 扩起来的内容     cJSON *name = NULL;                  cJSON *num = NULL;     cJSON *c_score = NULL;          /* 开始解析 */     student_json = cJSON_Parse(_JsonStudnetData);     if (NULL == student_json)     {         const char *error_ptr = cJSON_GetErrorPtr();         if (error_ptr != NULL)         {             fprintf(stderr, "Error before: %s ", error_ptr);         }         goto end;     }      /* 解析获取name得值 */     name = cJSON_GetObjectItemCaseSensitive(student_json, "name");     if (cJSON_IsString(name) && (name->valuestring != NULL))     {         memset(&_Stu->name, 0, STU_NAME_LEN*sizeof(char));         memcpy(&_Stu->name, name->valuestring, strlen(name->valuestring));     }      /* 解析获取num的值 */     num = cJSON_GetObjectItemCaseSensitive(student_json, "num");     if (cJSON_IsNumber(num))     {         _Stu->num = num->valueint;     }      /* 解析获取c_score的值 */     c_score = cJSON_GetObjectItemCaseSensitive(student_json, "c_score");     if (cJSON_IsNumber(c_score))     {         _Stu->c_score = c_score->valueint;     }  end:     cJSON_Delete(student_json); }  /******************************************************************************************************** ** 函数: PrintParseResult, 打印输出解析结果 **------------------------------------------------------------------------------------------------------ ** 参数:  ** 说明:  ** 返回:  ********************************************************************************************************/ static void PrintParseResult(const pStudentDef _Stu) {     printf("name: %s, num: %d, c_score: %d  ", _Stu->name, _Stu->num, _Stu->c_score); }  /******************************************************************************************************** ** 函数: SaveParseResult, 保存解析结果 **------------------------------------------------------------------------------------------------------ ** 参数: _Stu:需要保存的数据 ** 说明:  ** 返回:  ********************************************************************************************************/ static void SaveParseResult(const pStudentDef _Stu) {     char write_buf[512] = {0};     static int stu_count = 0;      /* 以可在文件末尾追加内容的方式打开文件 */ 	if((stu_fp = fopen("ParseResult.txt", "a+")) == NULL) 	{ 		printf("Open file error! "); 		return exit(EXIT_FAILURE); 	}       /* 按指定格式写入文件 */     snprintf(write_buf, 512, "name: %s, num: %d, c_score: %d ", _Stu->name, _Stu->num, _Stu->c_score);     size_t len = fwrite((char*)write_buf, 1, strlen(write_buf), stu_fp);      /* 文件位置指针偏移 */     fseek(stu_fp, len * stu_count, SEEK_SET);     stu_count++;      /* 关闭文件 */     fclose(stu_fp); }
  编译命令:gcc json_print.c cJSON.c -o json_print.exe -lwsocket32 gcc json_parse.c cJSON.c -o json_parse.exe -lwsocket32
  综合demo加了socket相关代码,本篇笔记主要介绍JSON数据的组包及解析。关于socket相关的内容不做过多解释。感兴趣的朋友可阅读往期socket相关的笔记:
  「socket应用」基于C语言的TCP天气客户端的实现
  以上基本贴出了本篇笔记所有demo代码,若不想复制或者懒得复制…也可添加我微信:li1459193463 ,回复暗号JSON相关demo ,获取demo工程。
  以上就是本次的分享,若有错误,欢迎指出,谢谢!

mac上哪款音乐播放器好用?推荐SwinsianforMacmac上哪款音乐播放器好用?推荐SwinsianforMacMac音乐播放器哪款好用?推荐SwinsianforMac,它是一款适用于macOS的精密音乐播放器,具有宽屏格式支持,MacPDF编辑工具PDFExpert功能介绍PDFExpert功能介绍PDFExpert批注功能详解随着数字化的发展,无纸化阅读得到越来越多人的响应。无论是小说还是文件,人们都开始青睐简单便携的电子阅读形式。PDF文件作为重mac版atom编辑器怎么安装?atom编辑器安装教程mac版atom编辑器怎么安装?atom编辑器安装教程mac版atom编辑器怎么安装?Atom可以帮助您用智能灵活的自动完成功能更快地编写代码,是一款不可多得的基于Web技术的桌面Mac协作工具妙笔WonderPenforMac如何切分多个窗口?日常写作中,我们有时需要打开另一个文档进行对照参考,比如正在写的小说情节需要参考之前另一章的内容,或者正在做翻译工作,需要有一个地方显示原文等等。这时,窗口切分功能就可以派上用场了Mac上强大的PDF文件搜索工具,PDFSearchMac有哪些新增功能?PDFSearchforMac是Mac平台上一款pdf文件搜索工具,PDFSearchmac破解版可以快速搜索文档参考书或者笔记,让你轻松访问任何信息,PDFSearchmac版还PS插件教程ps笔刷怎么安装?PS插件教程ps笔刷怎么安装?ps笔刷是Photoshop软件中的工具之一,通过ps笔刷的载入功能,就能刷出各种不同的效果来,可以说是ps用户最爱的功能之一。然而一些Photoshweb网页优化工具Scrutiny8功能详解Scrutiny是一款网站分析工具,它能够自动检测目标网站的坏链HTML验证描述Description标题Title等SEO信息,并具有强大的报告导出功能。且Scrutiny8优化名门修谱农历三月三,还有多少中国传统被慢慢淡忘?地菜煮鸡蛋三月三,地菜煮鸡蛋。今天又有几个人吃到了鸡蛋呢?由于商家的炒作,以及部分人崇洋媚外的文化不自信,导致情人节圣诞节等洋节泛滥。而很多中国人自己的传统节日则被逐渐冷落。甚至有为什么我们总觉得美国会倒却一直没倒?一提美国,十有八九是坏消息。从新冠疫情到枪击事件,从政府缺乏资金要关门到种族冲突社会动乱,从金融危机到贫民区,以至于我们常常会误以为米国将会分分钟倒掉。但是只要太阳第二天照常升起,名门修谱修谱最直接的2种心态,光宗耀祖和后世积德家谱家谱作为一个家族历史和文化的传承,当年在很长一段时间内,发展得并不好。随着改革开放,大批的台胞回国寻根,家谱文化又再次搬到了台面上。现在修家谱已经变得不再稀奇,再加上国家大力推英特尔对电脑芯片的统治力也在下降,不好意思7nm又开始挤牙膏了英特尔挤牙膏的传统由来已久,曾经不断翻炒14纳米工艺,一度挤牙膏挤的连苹果都看不下去了,开始自研基于ARM架构的电脑处理器。如今,好不容易搞到7纳米,官方宣布在工艺方面又遇到了一些
阿里巴巴病入膏肓,马云回归有用吗?网友阿里早就变味儿了关于阿里巴巴员工事件,谁听了不口露芬芳。更让人震惊的是,事情发生之后,受害人坠入万丈深渊,然而当事人却依然若无其事地照常上班,在工作群里谈笑风生,似乎一切都没有发生过,这着实让人感红警职教智能硬件电子电路基础版教材与配套视频资源开发完毕经过数月的精心准备,红警智能硬件电路基础与无人机可视化编程视频与在线直播课程即将上线啦!本系列课程是由公司硬件工程师团队自主开发并分享,适合零基础,电子电路基础等内容,了解智能家居欧界丨腾讯入股电动自行车充电桩小绿人,进一步扩大业务范围欧界报道根据最新季度的IT行业投资交易情况来看,疫情有所好转之后,整体科技行业的投资交易数量实现了平稳攀升,投资结构较为稳定。根据市场投资的总体行业分布情况来看,医疗健康行业最为热不打开微信就能自动抢红包?法院自动抢红包软件破坏微信正常运行,开发者构成不正当竞争核心提示利用自动抢红包软件快人一步,导致抢红包这种比手速拼运气的娱乐方式瞬间变了味儿。更严重的是,自动抢红包软件暗含侵权风险。近日,北京知识产权法院审结了一起与自动抢红包有关的不正看电视的人越来越少,手机和投影的时代,电视机成为摆设?如果说让你选择一种看电影或者电视剧的方式,你是会选择传统的电视还是手机或投影仪呢?电视机影响着几代人的成长,曾经的年代并没有很发达的科技,人们的娱乐方式也就不多,到了周末或者休息日五年前的老本卡顿是升级还是换新?五年前的老本卡顿是升级还是换新?办公室有一位同事,成天抱怨自己的电脑卡。(没错,这位同事就是我自己)当初图便宜,买了个很一般的笔记本,结果这才用了两年就反应慢了。更别提我五年前买的苹果要推iPadSE?Android平板将迎来大敌要说在此次疫情中获得了高速增长的行业,除了游戏娱乐外,在线教育同样可谓是一飞冲天,甚至顺带着将已经平淡了多年的平板电脑市场重新激活。随着沉寂许久的小米平板电脑产品线重新回归,rea荣耀play5tpro对比红米9,同样联发科G80的处理器,哪个更香呢?昨天这个荣耀发布的时候,我去看了一下这个处理器,其实还是挺陌生的,在我印象中好像只有红米9搭载这款处理器,其他手机我就不太清楚了,所以今天就把这两款手机拿来对比一波。首先我把价格说iPhone12电池不耐用?查看手机电池的健康状况,设置好后延长续航检查iPhone电池健康状况的方法,以免电量耗尽如果您的iPhone12似乎一直在低电量下运行,那么了解如何检查iPhone电池健康会很有用。您可能会发现您的电池健康状况实际上正在空调好伴侣,米家直流变频循环落地扇电池版开箱0。前言HELLO,大家好,我是Dior,米家风扇我已经有了好几个了,基本配置了每个房间,前段时间我还有一台可以变成台扇的米家变频落地扇E,可以当作空气循环扇来用,但还是要插电,就苹果新显示器评测屏幕的极致动态范围人类感性认识的组织方式这一认识赖以完成的手段不仅受制于自然条件,而且也受制于历史条件。德国文化批评家瓦尔特本雅明(WalterBenjamin)在1935年如此写道。他的意思是,我