zoukankan      html  css  js  c++  java
  • HTTP传输二进制初探

    【转】HTTP传输二进制初探

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

    【转】HTTP传输二进制初探

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

    从第一次接触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 ", 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. ", 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. ", argv[1]);
            exit(1);
        }
        if(feof(fp) == 1)
        {
            printf("too large of %s, please enlarge macro HEX_BUFFER. ", argv[1]);    
            exit(1);
        }
        fclose(fp);
        
        int i = 0;
        int j = 0;
        printf(" addr 0 1 2 3 4 5 6 7 8 9 a b c d e f ");
        for( ; i < read_count; i++, j++)
        {
            if( (j % 16) == 0)
            {
                printf(" 0x%-4x ", j);
            }
            printf(

     
  • 相关阅读:
    POJ 3126 Prime Path
    POJ 2429 GCD & LCM Inverse
    POJ 2395 Out of Hay
    【Codeforces 105D】 Bag of mice
    【POJ 3071】 Football
    【POJ 2096】 Collecting Bugs
    【CQOI 2009】 余数之和
    【Codeforces 258E】 Devu and Flowers
    【SDOI 2010】 古代猪文
    【BZOJ 2982】 combination
  • 原文地址:https://www.cnblogs.com/zxtceq/p/7154488.html
Copyright © 2011-2022 走看看