首页 > 编程知识 正文

苹果手机数据传输,两台旧苹果手机靠近传输数据

时间:2023-05-05 06:09:07 阅读:226987 作者:3589

一、Http协议中的chunked

一般http通信时会使用content_length头信息来表示服务器发送的文档内容长度,该头信息定义域http1.0协议RFC 1945 10.4章节中,浏览器接收到此头信息后接受完content_length中定义的产度字节后开始解析页面,但是如果服务器端有部分数据延迟发送则会出现浏览器白屏,用户体验差。

解决方案是在http1.1协议中EFC 2616中14.41章节中定义的Transfer_encoding:chunked的头信息。chunked编码定义在3.6.1中,所有HTTP1.1都应该支持使用chunked编码动态的提供body内容的长度的方式。进行chunked编码传输的http数据要在消息头部设置transfer_encoding:chunked表示content body将用chunked编码传输内容。根据定义,浏览器不需要等到内容字节全部下载完成,只要接收到一个chunked块就可以解析页面,并可以下载html中定义的页面内容,包括js,css,image等

采用chunked编码有两种选择一种是设定server的IO buffer长度让server自动flush buffer中的内容另一种是手动调用IO中的flush函数,不同的语言IO中都有flush功能:

php:ob_flush();flush()

perl:STDOUT->autoflush(1);

java:out.flush()

python:sys.stout.flush()

ruby:stdout.flush

采用http1.1的transfer_encoding:chunked并且把IO的buffer flush下来,一遍浏览器更早的下载页面配套资源,不可能在头中包含content_length域来指明报文体长度,此时就需要通过transfer_encoding域来确定报文体长度

二、Chunked编码的格式

chunked编码一般使用若干个chunk串联而成,最后一个表明长度为0的chunk表示结束。每一个chunked分为头部和正文两部分,头部内容制定下一段正文的字符总数(非零开头的十六进制数字)和数量单位(一般不写,表示字节),正文部分就是指定长度的实际内容,两部分之间用回车换行(CRLF)隔开,最后一个长度为0的chunk中的内容称为footer的内容,是一些附加的header信息(通常可以直接忽略)

chunked编码的基本方法是将大块数据分解成多块小数据,每块都可以自指定长度,其具体格式如下(BNF文法):
    Chunked-Body   =*chunk            //0至多个chunk
                    last-chunk         //最后一个chunk 
                    trailer                 //尾部
                    CRLF               //结束标记符

  chunk          = chunk-size [chunk-extension ] CRLF   
                       chunk-data CRLF
   chunk-size     =1*HEX
   last-chunk     =1*("0") [ chunk-extension ] CRLF

   chunk-extension= *( ";" chunk-ext-name[ "=" chunk-ext-val ] )
   chunk-ext-name = token
   chunk-ext-val  = token |quoted-string
   chunk-data     =chunk-size(OCTET)
  trailer        = *(entity-headerCRLF)   

解释:
    Chunked-Body表示经过chunked编码后的报文体。报文体可以分为chunk, last-chunk,trailer和结束符四部分。chunk的数量在报文体中最少可以为0,无上限;每个chunk的长度是自指定的,即,起始的数据必然是16进制数字的字符串,代表后面chunk-data的长度(字节数)。这个16进制的字符串第一个字符如果是“0”,则表示chunk-size为0,该chunk为last-chunk,无chunk-data部分。可选的chunk-extension由通信双方自行确定,如果接收者不理解它的意义,可以忽略。
    trailer是附加的在尾部的额外头域,通常包含一些元数据(metadata, meta means"about information"),这些头域可以在解码后附加在现有头域之后。

在数据部分有可能有注释字节,注释字节是分号分隔,如果发现注释的字节应该跳过。

摘自rfc:

A server using chunked transfer-coding in aresponse MUST NOT use the trailer for any header fields unless at least one ofthe following is true:

使用transfer_encoding作为响应的服务器不能使用trailer作为任何头部域,除非以下条件满足一条:

 

a)the request included a TE header fieldthat indicates "trailers" is acceptable in the transfer-coding of theresponse, as described in section 14.39; or,

a)请求包含一个TE头部域表示接收方可以接受trailers,请参见14.39章节

 

b)the server is the origin server for theresponse, the trailer fields consist entirely of optional metadata, and therecipient could use the message (in a manner acceptable to the origin server)without receiving this metadata. In other words, the origin server is willingto accept the possibility that the trailer fields might be silently discardedalong the path to the client.

服务器是原始响应服务器,trailer域包括所有可选数据,并且接受者可以使用消息(在某种意义上可以说接受原始服务器)而不用接受这些数据。换句话说原始服务器愿意接受trailer域可能在传递给客户端的过程中被默默地废弃掉

 

This requirement prevents aninteroperability failure when the message is being received by an HTTP/1.1 (orlater) proxy and forwarded to an HTTP/1.0 recipient. It avoids a situationwhere compliance with the protocol would have necessitated a possibly infinitebuffer on the proxy.

这样的设计阻止了这种失败:消息被一个http1.1或者更高版本的代理服务器转发给一个http1.0的接受者产生的失败。从而避免了这种情况:遵守协议的代理服务器必须拥有无限的buffer

 

An example process for decoding aChunked-Body is presented in appendix 19.4.6.

附件19.4.6中会给出一个解码chunked_body的http响应的例子

 

All HTTP/1.1 applications MUST be able toreceive and decode the "chunked" transfer-coding, and MUST ignorechunk-extension extensions they do not understand.

所有的http1.1应用必须能够接受和解码chunked transfer_encoding,而且在没有事先约定时必须忽略chunk_extension扩展

下面是抓包分析的chunked下载附件示例:


上面的一个chunk包没有包含chunk_extension。在chunksize之后就是rn。下面是最后一个chunk:


 

上述解释过于官方,简而言之,chunked编码的基本方法是将大块数据分解成多块小数据,每块都可以自指定长度,其具体格式如下:


其C语言的解码如下,java思路相同(以下代码摘自网络)

int nBytes;

char* pStart = a;    // a中存放待解码的数据

char* pTemp;

char strlength[10];   //一个chunk块的长度

chunk  : pTemp=strstr(pStart,"rn");

             if(NULL==pTemp)

             {

                      free(a);

                 a=NULL;

                     fclose(fp);

                     return -1;

             }

             length=pTemp-pStart;

            COPY_STRING(strlength,pStart,length);

            pStart=pTemp+2;

            nBytes=Hex2Int(strlength); //得到一个块的长度,并转化为十进制

                              

             if(nBytes==0)//如果长度为0表明为最后一个chunk

            {

                free(a);

                       fclose(fp);

                       return0;

               }

               fwrite(pStart,sizeof(char),nBytes,fp);//将nBytes长度的数据写入文件中

               pStart=pStart+nBytes+2; //跳过一个块的数据以及数据之后两个字节的结束符

               fflush(fp);

               goto chunk; //goto到chunk继续处理

 

 

 

如何将一个十进制数转化为十六进制

char *buf = (char *)malloc(100);

char *d = buf;

int shift = 0;

unsigned long copy = 123445677;

while (copy) {

         copy >>= 4;

         shift++;

}//首先计算转化为十六进制后的位数

if (shift == 0)

         shift++;

shift <<= 2; //将位数乘于4,如果有两位的话 shift为8

while (shift > 0) {

         shift -= 4;

         *(buf) =hex_chars[(123445677 >> shift) & 0x0F];

          buf++;

}

*buf = '';

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。