HTTP传输二进制初探

【转】HTTP传输二进制初探

http://www.51testing.com/?uid-390472-action-viewspace-itemid-233993

【转】HTTP传输二进制初探

上一篇 / 下一篇  2011-04-11 04:34:49 / 个人分类:知识

查看( 139 ) / 评论( 0 ) / 评分( 0 / 0 )

从第一次接触http协议的时候,不知是怎么回事,形成了这么一个错误的观点,认为http协议是个纯ASCII字符协议,也就是说在http流里是看不到二进制流的0x00值的。其实答案是:http协议里的content可以是纯二进制流。

http://my.chinaunix.net/space.php?uid=22568683&do=blog&id=84701

关于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


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HEX_BUFFER    1024

int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        printf("Usage: %s hex_file_path\n", argv[0]);    
        exit(1);
    }
    
    FILE *fp = NULL;
    fp = fopen(argv[1], "rb");
    if(fp == NULL)
    {
        printf("open %s error. please check the path of file,and make sure you have permission to read it.\n", argv[1]);
        exit(1);
    }    
    
    unsigned char hex_buf[HEX_BUFFER];
    memset(hex_buf, 0, HEX_BUFFER);
    
    int read_count = 0;
    
    read_count = fread(hex_buf, sizeof(unsigned char), HEX_BUFFER, fp);
    if(ferror(fp) != 0)
    {
        printf("read %s error.\n", argv[1]);
        exit(1);
    }
    if(feof(fp) == 1)
    {
        printf("too large of %s, please enlarge macro HEX_BUFFER.\n", argv[1]);    
        exit(1);
    }
    fclose(fp);
    
    int i = 0;
    int j = 0;
    printf("\naddr\t0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
    for( ; i < read_count; i++, j++)
    {
        if( (j % 16) == 0)
        {
            printf("\n0x%-4x\t", j);
        }
        printf(

时间: 2024-10-11 13:16:51

HTTP传输二进制初探的相关文章

C++和python利用struct结构传输二进制数据实现

网络编程中经常会涉及到二进制数据传输的问题,在C++中常用的传输方式有文本字符串和结构体封包.如果能将要发送的数据事先放进连续的内存区,然后让send函数获取这片连续内存区的首地址就可以完成数据的发送了,文本字符串如char型数组,以字节为单位,在内存中是顺序存储的,所以可以直接用send函数发送.但是如果要同时发送多个不同类型的数据时,它们在内存中存储的地址是随机的,不是顺序存储的,而且它们之间的相对位置也无法确定,这样就需要一种数据组织方式来明确各数据之间的相对位置.结构体显然就是一种的数据

如何提升mysql replication的性能&&多线程传输二进制日志

如何提升replication的性能: 延迟 : 对于mysql replication来说,在没有发生故障的情况下,出现master与slave数据不同步,延迟分为以下两种情况: 经常性延迟   : 异步同步的数据差距比较大 ,周期性的,循环. 暂时性延迟   : 突发情况,导致延迟 其主要原因就是: 网络带宽 I/O 如何减少replication延迟?? 1,最好使用内网或者专线链路传输binlog数据 (千兆网卡.还不够的话,bounding 技术,扩展带宽) 在my.cnf中强制使用内

MySQL如何传输二进制日志

MySQL Replication可以很方便的用来做应用的读扩展,也可以帮MySQL实现一定程度的HA方案.MySQL通过向备库传送二进制日志来实现Replication,本文将通过二进制日志相关源代码的主要接口来解释:“MySQL如何传输二进制日志,是主库推,还是备库拉?MySQL日志传输的实时性如何?”. 在MySQL Replication结构中,备库端初次通过CHANGE MASTER TO完成Replication配置,再使用start slave命令开始复制.更细致的,备库通过IO

C++和python使用struct传输二进制数据结构来实现

网络编程问题往往涉及二进制数据的传输.在C++经常使用的传输是文本字符串和分组结构. 假设该数据可以预先送入连续的内存区域,然后让send函数来获得的第一个地址,这一块连续的内存区就能完成传输数据.文本字符串,如char排列,字节.中是顺序存储的.所以能够直接用send函数发送. 可是假设要同一时候发送多个不同类型的数据时,它们在内存中存储的地址是随机的,不是顺序存储的,并且它们之间的相对位置也无法确定.这样就须要一种数据组织方式来明白各数据之间的相对位置.结构体显然就是一种的数据组织方式,使用

atitit.二进制数据无损转字符串网络传输

1. gbk的网络传输问题,为什么gbk不能使用来传输二进制数据 1 2. base64 2 3. iso-8859-1  (推荐) 2 4. utf-8 (不能使用) 2 1. gbk的网络传输问题,为什么gbk不能使用来传输二进制数据 gbk会造成信息丢失 由于有些字符在gbk字符集中找不到对应的字符,所以默认使用编码63代替,也就是?(问号)...gbk仅仅能兼容低位asc编码(英文字母),高位编码要使用来编码汉字了... 作者::老哇的爪子Attilax艾龙,EMAIL:[email p

json 二进制传输方案

json 传输二进制数组方案 json 是一种很简洁的协议,但可惜的是,它只能传递基本的数型(int,long,string等),但不能传递byte类型.如果想要传输图片等二进制文件的话,是没办法直接传输. 本文提供一种思路给大家参考,让大家可以在json传输二进制文件,如果大家有这个需求又不知怎么实现的话,也许本文能够帮到你.思想适用于所有语言,本文以java实现,相信大家很容易就能转化为自己懂得语言. 思路 1. 读取二进制文件到内存 2. 用Gzip压缩一下.毕竟是在网络传输嘛,当然你也可

使用erlang实现简单的二进制通信协议

最近实现的一种简单的协议以及工具,主要用于客户端服务端通讯传输二进制数据时,协议的解包与封包,具体如下:首先定义协议的格式,主要由三部分组成:        数据长度(数据部分长度+协议号长度):4个字节        协议号:2个字节        数据部分:2进制数据数据部分如果是字符串需要先计算字符串的长度,占2个字节,之后再紧跟字符串内容,以上三个部分构成一个完整的数据包,每次客户端服务端将数据进行以上格式的封包解包进行通信.下面是对一个协议号为10000的协议进行封包的例子:客户端向服

RFID 基础/分类/编码/调制/传输

不同频段的RFID产品会有不同的特性,本文详细介绍了无源的感应器在不同工作频率产品的特性以及主要的应用. 目前定义RFID产品的工作频率有低频.高频和甚高频的频率范围内的符合不同标准的不同的产品,而且不同频段的RFID产品会有不同的特性. 其中感应器有无源和有源两种方式,下面详细介绍无源的感应器在不同工作频率产品的特性以及主要的应用. 1. 低频(从125KHz到134KHz)   其实RFID技术首先在低频得到广泛的应用和推广.该频率主要是通过电感耦合的方式进行工作, 也就是在读写器线圈和感应

Hessian RPC示例和基于Http请求的Hessian序列化对象传输

本文主要介绍两个案例,第一个是使用Hessian来实现远程过程调用,第二个是通过Hessian提供的二进制RPC协议进行和Servlet进行数据交互,Hessian本身即是基于Http的RPC实现. 案例一: 1.准备工作 这里建立一个Maven项目,其中包含四个模块,父模块(仅用来聚合其它模块,不做实际使用),服务器端模块,客户端模块,API模块(远程过程接口,供服务器和客户端使用).目录结构见下图: 2.添加Hessian的依赖 由于客户端和服务器都要依赖Hessian的包,这里可以添加到父