【转】HTTP传输二进制 数据编码解码
来源:互联网 发布:手机编程工具排行榜 编辑:程序博客网 时间:2024/06/07 06:48
【转】HTTP传输二进制初探
关于HTTP传输ASCII文本内容的过程相信大家都应该容易理解,因为HTTP请求头和响应头都是以ASCII文本方式传输的。而对于HTTP传输二进制流的相关细节,其实没有我想象中的那么复杂,以前学习POP3和SMTP(这两个都是邮件传输协议)的时候,知道他们都只能传输ASCII文本,如果要在邮件中加入附件,如一张图片(图片文件就是二进制文件)那就得先对图片文件转码,即将邮件协议不能传输的二进制数据流转换成可被邮件协议传输的ASCII数据流,其中用的最多的转换就是BASE64编码转换。其实BASE64编码转换也同样适合于HTTP协议,只有你在转换后将HTTP响应头中的Transfer-Encoding设置为base64,当然如果客服端浏览器不支持base64编码那这种转换也是徒劳的,不过幸好现在几乎所有浏览器都支持BASE64(你能用浏览器查看邮件中的附件就是证据)。
不过话又回来,既然HTTP能够直接支持二进制的数据流传输,那我们又何必绕着弯子,走冤枉路呢?
如果你和一样,也对HTTP能直接传输二进制感到疑问,那么下面的内容会很对你胃口。
我们以一张图片的传输来说明这个问题:
http://gimg.baidu.com/img/gs.gif 这是百度主页上一张非常小的图片的链接地址 即右侧
图片
我们用到的工具有:
Firefox 浏览器
Firebug 一个非常不错的web调试器,Firefox插件
Ethereal 网络抓包工具
如果你对上面三个工具不是很了解,建议你先去google一下。然后再来阅读。
下面是我们在Firefox地址栏里面输入http://gimg.baidu.com/img/gs.gif 回车后,Firefox默默地为我们做的事情。关于HTTP通行的细节请参阅我以前的文章
http://blog.chinaunix.net/u3/104217/showart.php?id=2075210
http://p.99081.com/unix/http_protocol_summary.html
GET /gs.gif HTTP/1.1
Host: gimg.baidu.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
当Firefox发出该请求后,服务器接收并分析该请求,经分析后得出客服端浏览器请求的文件(或者说页面)为/img/gs.gif (第一个斜杆代表服务器根目录),于是服务器(百度的HTTP服务器为Apache)从服务器主机的硬盘(或者直接从内存的缓冲区)中读出该图片(注意哦,直接读二进制流),并将其拼接到HTTP响应头后,然后把这片数据(我指的是HTTP响应头加上图片的二进制数据)拷贝到TCP的发送缓冲区(也就是调用send函数)。
下面即位客服端收到的从服务器端发来的数据流:
我们还是先来分析一下响应头
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2009 13:43:15 GMT
Server: Apache
Last-Modified: Fri, 11 Aug 2006 04:20:15 GMT
Accept-Ranges: bytes
Content-Length: 91
Cache-Control: max-age=315360000
Expires: Fri, 25 Oct 2019 13:43:15 GMT
Connection: close
Content-Type: image/gif
注意最后一个字段 Content-Type:image/gif 这说明传输的是一个image对象,该对象为gif格式。另外我们还有记下Content-length:91 这说明传输的数据(即gs.gif图片)的大小为91个字节,此外我们还发现响应头中并没有Transfer-Encoding这个字段,这说明传输的数据没有经过任何形式的编码转换,传输的就是源文件的内容。
请认真查看上图中蓝底部分,在蓝底的最后那一行,有两个连续的 0d 0a 0d 0a ,这说明HTTP响应头已经结束,接下来的内容为传输的文件。好啦,那接下来当然是要分析传输的文件到底是啥东西了。请看下图
图中蓝底的部分即为传输的数据流(即传输的文件),这些是什么东西,我也搞不懂,(估计只有搞图片压缩算法的人能够看得懂),不过没关系,我们可以先把图片保存在本地,然后用一个十六进制查看软件打开该图片,即可知道其中的奥秘。
下面是用UltraEdit打开该图片后的截图
请比较一下上面两张图片是不是有很多相同的地方呀,其实上面两张图中,第一张中的蓝底部分就是第二张中的数据。这下你应该明白了吧,其实HTTP传输的就是图片文件的二进制编码,Apache没有对二进制文件进行任何形式的编码转换。我们还可以计算一下这个图片的大小:16 * 5 + 11 = 91 (也就是 0x5a – 0x00 = 0x5a),正好和HTTP响应头中的Content-Length相等。
如果没有UltraEdit等十六进制编辑器,我写了个简单的程序以供查看,下面是源码:
check_hex.c
http://blog.csdn.net/chen1403876161/article/details/51546653
http://blog.csdn.net/acmdream/article/details/71334169
#include <stdio.h> #include <string.h> long int encode( char *src,long int src_len, char *dst) { long int i = 0, j = 0; char base64_map[65] = "BADCFEGHIJKLMNOPQRSTUVWXYZbadcfeghijklmnopqrstuvwxyz0123456789+/"; for (; i < src_len - src_len % 3; i += 3) { dst[j++] = base64_map[(src[i] >> 2) & 0x3F]; dst[j++] = base64_map[((src[i] << 4) & 0x30) + ((src[i + 1] >> 4) & 0xF)]; dst[j++] = base64_map[((src[i + 1] << 2) & 0x3C) + ((src[i + 2] >> 6) & 0x3)]; dst[j++] = base64_map[src[i + 2] & 0x3F]; } if (src_len % 3 == 1) { dst[j++] = base64_map[(src[i] >> 2) & 0x3F]; dst[j++] = base64_map[(src[i] << 4) & 0x30]; dst[j++] = '='; dst[j++] = '='; }else if (src_len % 3 == 2) { dst[j++] = base64_map[(src[i] >> 2) & 0x3F]; dst[j++] = base64_map[((src[i] << 4) & 0x30) + ((src[i + 1] >> 4) & 0xF)]; dst[j++] = base64_map[(src[i + 1] << 2) & 0x3C]; dst[j++] = '='; } dst[j] = '/0'; printf("encode length:%ld/n",j); return j; } long int decode(char *src, long int src_len, char *dst) { long int i = 0, j = 0; unsigned char base64_decode_map[256] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255, 255, 1, 0, 3, 2, 5, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 27, 26, 29, 28, 31, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; for (; i < src_len; i += 4) { dst[j++] = base64_decode_map[src[i]] << 2 | base64_decode_map[src[i + 1]] >> 4; dst[j++] = base64_decode_map[src[i + 1]] << 4 | base64_decode_map[src[i + 2]] >> 2; dst[j++] = base64_decode_map[src[i + 2]] << 6 | base64_decode_map[src[i + 3]]; } dst[j] = '/0'; printf("decode length :%ld/n",j); return j; } int main(){ int num = 11111; printf("int:%ld/n",sizeof(int)); char num_char[100]; char num_char_b64[200]; memset(num_char,'/0',100); memcpy(num_char,&num,4); printf("content_to_be_encoded:%s/n",num_char); int len = encode(num_char,4,num_char_b64); printf("content_encoded:%s/n",num_char_b64); int len2= decode(num_char_b64,len,num_char); printf("%s/n",num_char); memcpy(&num,num_char,4); printf("int:%d/n",num); }我的游戏中心服务端的HTTP server,客户端请求采用了表单Form的形式提交数据,服务端利用Boost解析字符数据,然后保存到数据库,再利用protoBuf打包数据,发送二进制数据内容的响应给客户端处理。实现了自定义数据格式和数据流的传输。
- 【转】HTTP传输二进制 数据编码解码
- Base8编码:通过数字传输二进制数据
- 关于http传输字符的编码和解码
- http发送数据的解码与编码
- Node.js, 使用 Buffers 操作,编码、解码,二进制数据。
- HTTP传输二进制初探
- 在http协议中传输二进制的数据--base64实现
- iOS 使用http POST方法传输二进制数据
- 嵌入式开发中http传输二进制数据的注意事项
- 在http协议中传输二进制的数据--base64实现
- HTTP传输编码
- Mediacodec编码UDP传输,接收到数据不能解码显示的问题
- soap协议传输二进制数据
- xml 二进制数据 传输处理
- Android Intent传输二进制数据
- 中文数据网络传输转码与解码过程浅析
- http,javascript的编码解码
- IOS HTTP 传输数据
- hiho一下 第157周 二进制小数
- F1V3.0-图形-绘图类库快速搭建一个页面绘图应用实例
- USACO Section 1.1 Broken Necklace
- GSON
- 小结
- 【转】HTTP传输二进制 数据编码解码
- ZooKeeper源码分析
- c#中ArrayList 与string 、string[]的转换
- Linux 文件系统(一)---虚拟文件系统VFS----超级块、inode、dentry、file
- JSP 结构
- DELETE_FAILED_INTERNAL_ERROR Error while Installing APK
- AngularJS的ui-router第一次点击激活路由加载页面,再次点击就没用,如何实现每次点击都激活加载路由一次
- STL常用函数复习之————multiset
- ubuntu 安装 tensorflow