近期应项目要求,需要在嵌入式设备上实现将数据上传至服务器,查找了许多资料,现在将整个过程所需要的知识整理下来,以备后续查找。硬件环境下位机:基于Linux的嵌入式开发硬件 上位机:web服务器(PC端)HTTP协...
 
                
近期应项目要求,需要在嵌入式设备上实现将数据上传至服务器,查找了许多资料,现在将整个过程所需要的知识整理下来,以备后续查找。
硬件环境
下位机:基于Linux的嵌入式开发硬件
 上位机:web服务器(PC端)
HTTP协议简介
HTTP即Hyper Text Transfer Protocol (超文本传输协议),是一种基于TCP/IP通信协议来传递数据 (HTML 文件,图片文件,查询结果等)。
HTTP协议的几种请求方法
在HTTP1.1中,总共有8种请求方法(也叫动作),用来表明对Request-URL指定的资源的不同操作方式。HTTP协议的几种请求方法如下表所示:
 
 HTTP服务器至少应该实现GET和HEAD/POST方法,其他方法都是可选的,此外除上述方法,特定的HTTP服务器支持扩展自定义的方法。大部分时候,需要使用的只有GET和POST。针对项目设计的C语言代码主要实现的功能即为上述方法的POST功能。
四种常见的 POST 提交数据方式
在使用post,put,delete,options等方法的时候,他们都有方法体body,用来存储数据。而body的类型可以有:form-data、x-www-form-urlencoded、raw、binary
form-data
就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息;由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。
x-www-form-urlencoded
这是最常见的POST提交数据的方式了。原生的form表单,如果不设置enctype属性,最终就是以application/x-www-form-urlencoded方式提交数据。会将表单内的数据转换为键值对,比如,name=java&age = 23。
raw
可以上传任意格式的文本,可以上传text、json、xml、html等。
binary
相当于Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。
而本次由于项目需要,使用的是json方式传递数据。
实现思路
由于HTTP协议是基于TCP通信的,故可以有如下多种方式实现HTTP传输协议:
 1)使用DTU
 2)使用AT命令
 3)第三方开源库
 4)使用socket通信
本次使用第三方库curl来实现,curl是一个功能强大的网络工具,它能够通过http、ftp等方式下载文件,也能够上传文件。这类库语句简单,能够省去许多开发的时间,提高开发效率。
实现过程
安装wireshark抓包软件
wireshark用于调试http协议和分析http原始数据。
 wireshark软件的下载链接如下:
 http://soft.wuseng.net/11/3438.html?tab=5752682
确定抓包过程中,上位机或下位机的IP地址
下位机地址:
 按win+R打开系统运行界面,输入cmd打开系统终端,在终端中输入指令ipconfig查看本机IP地址:
 
 上位机地址:
 由于本次项目使用已知的服务器,所以此处的IP地址是已知的。若需要向一个网站上传数据,也可以通过终端ping+网站域名的方式,得到网站的IP地址。如CSDN的IP地址为101.200.35.175。
 
设置过滤条件
上一步中已经知道了上位机和下位机的IP地址,即可在wireshark的filter一栏中输入以下过滤条件:
 http and ip.addr == 192.168.1.110 and tcp.port == 80
 
 http:指定网络协议
 ip.addr == 192.168.1.110:指定服务器ip地址,请根据实际情况替换。
 tcp.port == 8080,指定端口号,请根据实际情况替换。
安装JSON包和CURL工具
json安装包链接:https://pan.baidu.com/s/1BDc2JldxTEmmcxwdqesvTw
 提取码:54jg
sudo tar -xvf tar xvf json-c-0.9.tar.gz
cd  xvf json-c-0.9.tar.gz
./configure
make
sudo make install
安装curl
sudo apt install curl
sudo apt install libcurl4-openssl-dev
编写HTTP传输代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "/usr/local/include/json/json.h"
 
#define POSTURL    "xxx.xxx.xxx.xxx" 	//需要接收消息的IP地址
 
int main(int argc,char *argv[])
{
	//1、创建一个json数组对象,就可以理解为外面那个大容器[]
	struct json_object *arr=json_object_new_array();
	//2、创建两个字符串对象,可以以理解为[]中的两个小容器{}
	struct json_object *str1=json_object_new_object();
	//struct json_object *str2=json_object_new_object();
	//3、把要存放的数据转为对象
	struct json_object *value1=json_object_new_int(1);
	struct json_object *value2=json_object_new_int(1);
	struct json_object *value3=json_object_new_int(1);
	struct json_object *value4=json_object_new_int(1);
	struct json_object *value5=json_object_new_double(118.846597);
	struct json_object *value6=json_object_new_double(32.027024);
	struct json_object *value7=json_object_new_double(12.18);
	//4、把数值对象添加到字符串对象中
	json_object_object_add(str1,"carId", value1);
	json_object_object_add(str1,"carType", value2);
	json_object_object_add(str1,"carStatus", value3);
	json_object_object_add(str1,"driveStatus", value4);
	json_object_object_add(str1,"longitude", value5);
	json_object_object_add(str1,"latitude", value6);
	json_object_object_add(str1,"carSpeed", value7);
	//5、把数组对象转为字符流进行发送
	const char *temp=json_object_to_json_string(str1);
	
	CURL *curl;
	CURLcode res;
 
	struct curl_slist *http_header = NULL;
 
	curl = curl_easy_init();
	if (!curl)
	{
		fprintf(stderr,"curl init failed\n");
		return -1;
	}
 
        curl_easy_setopt(curl,CURLOPT_URL,POSTURL); //url地址
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); //不检查ssl,可访问https
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);  //不检查ssl,可访问https
        curl_easy_setopt(curl,CURLOPT_POSTFIELDS,temp); //post参数
        curl_easy_setopt(curl,CURLOPT_POST,1); //设置问非0表示本次操作为post
        curl_easy_setopt(curl,CURLOPT_VERBOSE,1); //打印调试信息
 
        http_header = curl_slist_append(NULL, "Content-Type:application/json;charset=UTF-8");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);
 
        curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1); //设置为非0,响应头信息location
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);//接收数据时超时设置,如果10秒内数据未
  
	res = curl_easy_perform(curl);
 
	if (res != CURLE_OK)
	{
		switch(res)
		{
			case CURLE_UNSUPPORTED_PROTOCOL:
				fprintf(stderr,"不支持的协议,由URL的头部指定\n");
			case CURLE_COULDNT_CONNECT:
				fprintf(stderr,"不能连接到remote主机或者代理\n");
			case CURLE_HTTP_RETURNED_ERROR:
				fprintf(stderr,"http返回错误\n");
			case CURLE_READ_ERROR:
				fprintf(stderr,"读本地文件错误\n");
			default:
				fprintf(stderr,"返回值:%d\n",res);
		}
		return -1;
	}
 
	curl_easy_cleanup(curl);
	printf("\n");
	return 0;
}
编译:
gcc http.c -o http -ljson -lcurl
接收消息测试与分析
输入过滤条件,点击apply,并运行以上代码,可以抓取到两个数据包:
 
 分别是下位机发送的HTTP请求和上位机发回的HTTP响应。Source一栏表示发送方的IP地址,Destination一栏表示接收方也就是服务器的IP地址,Protocol表示遵循的协议,Length表示数据长度,Info表示数据内容。
 在任意数据包上右键点击“追踪流”、“HTTP流”,可以看到发送与接收到的消息。
 
 至此,HTTP发送测试完成。
参考博客
https://blog.csdn.net/songfeihu0810232/article/details/54892149
 https://blog.csdn.net/weixin_42399752/article/details/94744785
 https://blog.csdn.net/xukai871105/article/details/31008635
本文标题为:基于Linux的嵌入式设备通过CURL实现HTTP POST方式向服务器传递JSON数据(C语言)(原理+实现过程+代码)
 
				
         
 
            
        基础教程推荐
- C++高级数据结构之并查集 2023-04-20
- C++类和对象到底是什么 2022-11-12
- C语言文件操作与相关函数介绍 2023-06-13
- 使用VS2022开发在线远程编译部署的C++程序(图文详解) 2023-01-15
- C语言实现简易停车场管理系统 2023-03-13
- C/C++ Qt StatusBar底部状态栏应用教程 2023-01-10
- 使用C/C++读写.mat文件的方法详解 2023-03-05
- C语言预编译#define(预处理) 2023-04-03
- 漫画讲解C语言中最近公共祖先的三种类型 2023-01-01
- 如何告诉 MinGW 链接器不要导出所有符号? 2022-10-07
 
    	 
    	 
    	 
    	 
    	 
    	 
    	 
    	 
						 
						 
						 
						 
						 
				 
				 
				 
				