一、JOSN的概念:
1.cJSON简介
- JSON(JavaScript Object Notation)是一种轻量级的文本数据交换格式, 易于让人阅读。同时也易于机器解析和生成.。JSON虽然是Javascript的一个子集, 但JSON是独立于语言的文本格式,并且采用了类似C语言的一些习惯。
- 为什么我们要使用cJSON呢? 我们在传输数据时, 如果只有一个数据比如温度t = 26.53 .我们传输过去一定会知道这个数据是什么。此时如果数据既有温度和湿度. 那么我们传输过去的是俩个字符串. 此时是不能分辨出温度还是湿度的值。而cJSON简洁又简单,而且效率又快,cJSON工程文件也非常简单,仅一个.C文件和一个.h文件!并且文件体积大小不到K。源码思路也非常清晰,也非常适合研究。
2.JSON 语法
cJSON 的格式为: {//花括号内保存对象
“sn”: “sds123”,//数据由逗号分隔
“tem”: “12.2”,//名称在前,数据在冒号后面
“time”: “13:00”
}
3.cJSON下载(Linux环境下)
我们可以通过此链接下载cJOSN
https://sourceforge.net/projects/cjson/
当我们下载好cJSON只需要把.C文件和.h文件包含文件拷贝到我们工程目录下,我们就可以使用了。
4.cJSON的使用
4.1使用方法:
1.通过gcc直接编译 :
gcc test.c cjson.c
但每次编译两个文件有些麻烦,所以接下来,我们使用动态库。
2.动态库
这里我们不细讲动态库,想学习的可以参考下一篇博客。
gcc test.c -lcjson -L.
二.cJSON库函数的简介
1、cJSON *cJSON_CreateObject();
//创建一个json对象,返回一个cJSON结构体类型的指针。
2.void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
//向json对象中添加一对元素,object为json对象,string为加入一对元素中的name,item为加入一对元素中的value。
3. cJSON_AddNumberToObject(json,"temp",30.56);
//向json对象中添加一个数
4.cJSON *cJSON_CreateString(const char *string);
//创建一个字符串对象,传入一个char *类型的字符串,返回一个cJSON结构体类型的指针。
5.void cJSON_AddItemToArray(cJSON *array, cJSON *item);
//向数组对象中添加一个元素,传入参数array为cJSON *结构体类型的指针,为数组对象,item为添加如数字对象中的对象指针。
6.char *cJSON_Print(cJSON *item);
//将一个cJSON结构体代表的json对象转换为一个json格式的字符串。
7.、void cJSON_Delete(cJSON *c)
//释放一个cJSON对象占用的内存空间。
三. cJSON函数库的使用
我以socket以客户端发送,服务器端接收解析为例:
客户端:
int main(int argc,char*argv[])
{
int socket_fd=-1;
struct sockaddr_in serv_addr;
int rv;
char buf[1024];
char *buff;
FILE *fp;
cJSON *json = cJSON_CreateObject();//创建一个json对象
cJSON_AddItemToObject(json,"number",cJSON_CreateString("PRI001"));//向json中添加序列号
cJSON_AddItemToObject(json,"time",cJSON_CreateString("2021-02-19 21:01:30"));//向json中添加日期
cJSON_AddNumberToObject(json,"temp",30.56);//向json中添加温度值
// buff = cJSON_Print(json);
fp = fopen("create.json","w");
fwrite(buff,strlen(buff),1,fp);
buff = cJSON_Print(json);
socket_fd=socket(AF_INET, SOCK_STREAM ,0);
if(0>socket_fd)
{
printf("create socket failure:i'%s'\n",strerror(errno));
return -1;
}
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_port = htons(SERVER_PORT);
inet_aton(SERVER_IP,&serv_addr.sin_addr);
if(connect(socket_fd, (struct sockaddr *)&serv_addr,sizeof(serv_addr))<0)
{
printf("connect to server [%s:%d] failure:%s\n",SERVER_IP,SERVER_PORT,strerror(errno));
return 0;
}
if( write(socket_fd,buff,strlen(buff))<0)
{
printf("cinnect to server[%s:%d] failure:'%s'\n",SERVER_IP,SERVER_PORT,strerror(errno));
goto clearup;
}
memset(buf,0,sizeof(buf));
rv=read(socket_fd,buf,sizeof(buf));
if(0>rv)
{
printf("read data from server failure:'%s'\n",strerror(errno));
goto clearup;
}
else if(0==rv)
{
printf("client connect to server get disconnected\n");
goto clearup;
}
printf("raed:%d bety data from server:%s\n",rv,buf) ;
//free(buff);
fclose(fp);
//释放json结构所占用的内存
cJSON_Delete(json);
clearup:
close(socket_fd);
}
服务器端:
void print_usage(char *progname)
{
printf("%s usage: \n", progname);
printf("-p(--port): sepcify server listen PORT. \n");
printf("-h(--help): printf this help information. \n");
return ;
}
int main(int argc, char **argv)
{
int sockfd = -1; //socket 返回值
int rv = -1; //connect 返回值
struct sockaddr_in servaddr; //
struct sockaddr_in cliaddr; //
socklen_t len;
int port = 0;
int clifd;
char buf[1024];
int i;
int size;
cJSON *tnode = NULL;
cJSON *node = NULL;
struct option opts[] ={
{"port", required_argument, NULL, 'p'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
int ch;
printf("start parser agguments\n");
while( (ch=getopt_long(argc, argv, "p:h", opts, NULL)) != -1)
{
switch(ch)
{
case 'p':
port = atoi(optarg);
break;
case 'h':
print_usage(argv[0]);
break;
}
}
if( !port)
{
print_usage(argv[0]);
return 0;
}
//一个socket连接由四个元素组成:源ip,端口, 目的ip,端口
//我们现在已经绑定了目的ip和端口. 源ip和端口并未指定
//客户端如果想通过指定ip与端口来连接服务器,调用bind()
//一般客户端不调用bind(), 这是操作系统内核会自动分配
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
printf("Create socket failure: %s\n", strerror(errno));
return -1;
}
printf("Create socket[%d] successfully!\n", sockfd);
memset(&servaddr, 0, sizeof(servaddr)); //将结构体内存清零
servaddr.sin_family=AF_INET; //设置为IPv4.
servaddr.sin_port = htons(port); //注意:此处不能直接等于"12345", 这是本机字节序, 网络中传输的是网络字节序, 使用htons 转换, s是俩个字节的意思.
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY就是 0000
//inet_aton(servip, &servaddr.sin_addr); // server:172.17.53.29 这样只监听这个IP ifconfig来的 正常的要监听所有IP
//服务器一般只绑定端口, IP 设置为INADDR_ANY 监听所有IP.
int on = 1;
if((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0 )
{
perror("setsockopt failed");
exit(EXIT_FAILURE);
}
rv=bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if(rv < 0)
{
printf("Socket [%d] bind on port[%d] failure: %s\n", sockfd, port, strerror(errno));
// printf("create socket failure: %s\n", strerror(errno));
return -2;
}
listen(sockfd, 13); //backlog 是正处于连接客户端所保持的个数.
printf("Start to listen on port [%d]!\n", port);
// printf("Connect to server[%s:%d] successfully!\n",servip, port);
while(1)
{
printf("Start caaept new client incoming...");
clifd = accept(sockfd, (struct sockaddr *)&cliaddr, &len);
if(clifd < 0)
{
printf("Accept new client failure: %s\n", strerror(errno));
continue;
}
printf("Accept new client[%s:%d] successfully\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
memset(buf, 0, sizeof(buf));
rv = read(clifd, buf, sizeof(buf));
printf("111 buf:%s\n", buf);
if( rv < 0 )
{
printf("Read data from clien by sockfd[%d] failure: %s\n", clifd, strerror(errno));
close(clifd);
continue;
}
else if( rv == 0 )
{
printf(" Clifd[%d] get disconnected\n", clifd);
break;
}
else if( rv > 0 )
{
size = cJSON_GetArraySize(node);
for(i=0;i<size;i++)
{
tnode = cJSON_GetArrayItem(node,i);//json解析
if(tnode->type == cJSON_String)
{
printf("value[%d]:%s\n",i,tnode->valuestring);
}
else
{
printf("node' type is not string\n");
}
}
}
rv = write(clifd, MSG_STR, strlen(MSG_STR));
if( rv < 0 )
{
printf("Write to client by sockfd[%d] failure: %s\n", sockfd, strerror(errno));
close(clifd);
continue;
}
printf("Close client socket[%d]\n", clifd);
close(clifd);
}
}