首頁>技術>

前言

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.\n");    }/* 異常情況統一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會比較好,畢竟去掉空格就可以減小一定程度的通訊負擔。

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\n", 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);}

解釋見註釋。

執行演示:

gcc json_print.c cJSON.c -o json_print.exe -lwsocket32gcc json_parse.c cJSON.c -o json_parse.exe -lwsocket32

綜合demo加了socket相關程式碼,本篇筆記主要介紹JSON資料的組包及解析。關於socket相關的內容不做過多解釋。感興趣的朋友可閱讀往期socket相關的筆記:

29
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 基於WebGL的線上3D建模與互動指令碼開發 ThingJS