HTTP上传文件的总结

因为工作中做个客户端,需要和web后端打交道,用的都是http的接口。对http接口也不是很熟,就自己搭个环境测试了解这个过程。

后端就随便选用一个可以用的框架就好了。框架反正都是调用api基本都是一个套路,平台搭建好了调调接口解析一下就ok了。而这里主要着重于http协议进行分析,从而对http有直观的认识。

1.整体框架说明

整个网络通信采用http通信。后面会按几个功能进行单独分析。

客户端这边用c++,使用libcurl的库,运行在某类U系统上。编译这边的环节省略,一般系统会自带有这个库。关于这个库的使用,建议参考官方文档和test。

https://curl.haxx.se/libcurl/c/

服务器这端采用apache+php的框架,跑在ubuntu系统上。

然后整个过程保持网络畅通。。。。

2.工具使用说明

2.1.如何查看http报文

方法1

libcurl库提供一个接口选项:

curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

在执行前打开此接口即可查看通信过程的信息,也可以看到报文内容

方法2

服务器端查看报文。可以在请求脚本里将接收到的报文定向输出到文件。

方法3

借助网络抓包工具。抓包工具有很多,这里可以用wireshark。wirshark的功能比较多,这里我用过滤器去过滤出我需要的监听信息就好了。
因为我知道服务器的ip,所以可以在过滤器里填写:

ip.dst == xx.xx.xx.xx  or ip.src == xx.xx.xx.xx

然后监听,这个过程中请求的数据就会被捕捉下来了

其实这个工具用来了解整个网络协议是挺好的,然后我们只需要http/txt,选中这个工具。

这里可以查看流数据信息以及通信流程。具体流数据的解析详见后面。

2.2.命令行发送http请求

发送http请求可以是用curl工具,本身他就是libcurl库的一个产物工具。它相当于把基本功能都集成在一个命令里了。

如果使用curl详见man参考文档或者其他资料。如果要查看通信的详细过程可以加上-v参数。

3.POST上传文件

这里不再用简单的get或post请求来做示范,而是来解释发送文件。为此特地找了个大小较大的XML文件作为发送数据,服务器仅接受数据,应答随意。这里用表单的方式进行数据填充,之前还是过直接填入到报文主体,也是ok的。其实说到底还是一个数据解析的问题。

1.客户端

curl命令

curl命令中又一个-F 的参数将会以multipart/form-data发送POST数据;如果是发送文件的话,需要在参数前面加@。

客户端代码
bool send_postReq(const char *url, const char *filename)
{
    bool ret = true;
	char head1[] = "Content-Type:multipart/form-data"; //采用表单的方式
	char head2[] = "Accept: */*";
	CURL *curl;
	CURLcode rcode;
	struct curl_httppost *formpost = NULL;
	struct curl_httppost *lsptr = NULL;
	struct curl_slist *headers = NULL;
	
    curl_global_init(CURL_GLOBAL_DEFAULT);

	headers = curl_slist_append(headers, head1);
	headers = curl_slist_append(headers, head2);
	
	curl = curl_easy_init();
	if (curl == NULL)
	{
	    goto lb1;
	    ret = false;
	 }
    curl_global_cleanup();

    curl_formadd(&formpost, &lsptr,           //填写表单
			CURLFORM_COPYNAME, "file",
			CURLFORM_FILE, filename,
			CURLFORM_CONTENTTYPE, "text/xml",
			CURLFORM_END);

	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

	curl_easy_setopt(curl, CURLOPT_URL, url);

	curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
	
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out);

	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_respData);

	#ifdef CURL_DEBUG
	    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
	#endif		
	
     //ssl
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
    
    if (curl_easy_perform(curl) != CURLE_OK)
    {
        printf("%s\n", curl_easy_strerror(rcode));
        ret = false;
    }

    curl_formfree(formpost);

	curl_slist_free_all(headers);
lb1:
	curl_easy_cleanup(curl);
	
    return ret;
}

这里有几个比较坑的点:

1.这种easy模式采用的是阻塞的,也就是说当网络产生卡顿的时候,有一定几率会被阻塞到curl_easy_perform这个函数里。最坑的是即使网络恢复,也不能出来。所以这里解决这个问题有几个方式。一个是curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L)来设置超时时间。而是开多线程来管理每个curl_easy_perform,同时万一被阻塞了还要想办法终止它。还有一种是可以参考multi模式。

2.关于ssl的问题
之前设置CURLOPT_SSL_VERIFYPEER和CURLOPT_SSL_VERIFYHOST两个选项的值一直没用,其实参考官方test会发现,是对curl_global_init(CURL_GLOBAL_DEFAULT)的设置值有要求。这种配置情况下,http和https是通用的。

3.curl_formadd官方好像并不推荐用这个???

2.分析

连接和断开

http是建立与tcp上的,因此一下子就能看到3次握手4次挥手的协议。

三次握手:
在这里插入图片描述
四次挥手:在这里插入图片描述
整个过程:
在这里插入图片描述

http的数据

从wireshark上看很明显发现是被是数据被分割发送了。这个数字应该和最大发送单元(MTU)有关。我们看到的数据单位是1500,可以从seq来得知当前收到数据的位置。当收到最后一个包的时候,就被标示成了http/xml协议。
在这里插入图片描述
这里的分包其实就是TCP的拆包和滑动窗口来接受数据。

报文主体格式

关于文件大小:
通过http显示报文得知总共数据大小:285819.而实际发送的文件大小是:285599.这里的大小是指报文主体内容的大小。可以查看数据信息,从First boundary这里到xml开始前的值是正好是两个的差值。
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019111810501636.png
然后最后看一下用表单发送文件的格式:
在这里插入图片描述在这里插入图片描述
到这里其实已经非常清楚这个表单发送文件,是如何发送的了。文件的数据被填充到了前面关于描述content的信息之后,直接插入到后面的文本里。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值