TCP通信流程解析(以访问一次百度网站为例)(包括以太网帧头、IP头、TCP头、UDP头)

B/S通信简述
整个计算机网络的实现体现为协议的实现,TCP/IP协议是Internet的核心协议,HTTP协议是比TCP更高层次的应用层协议。

HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP的初衷是为了提供一种发布和接收HTML页面的方法。

浏览器(Web Browser)负责与服务器建立连接,下载网页(包括资源文件及JS脚本文件)到本地,并最终渲染出页面。JS脚本文件运行在客户端,负责客户端一些行为响应或预处理,例如提交表单前的数据校验、鼠标事件处理等交互。由此可见,浏览器(Browser)一方面充当了C/S通信架构中C角色,另一方面它是HTML/JavaScript的解析渲染引擎(Analyze Render Engine)。

当在浏览器地址栏敲入“http://www.baidu.com/”并按下回车键时,浏览器中将呈现出百度搜索引擎首页。这样一种情景我们再熟悉不过,本文通过wireshark抓取这一过程的数据包,结合TCP协议分析HTTP通信的基本流程。

IP & MTU
本文用到的抓包工具为wireshark,它的前身是赫赫有名的Ethereal。wireshark以太网帧的封包格式为:

----------------------------------------------------------------------------------------------------

Frame=Ethernet Header +IP Header +TCP Header +TCP Segment Data

----------------------------------------------------------------------------------------------------

(1)Ethernet Frame =Dst Physical Address(6 Byte)+ Src Physical Address(6 Byte)+Type(2 Byte)+data(46~1500 Byte)+FCS(4 Byte),以太网帧头以下称之为数据帧。

(2)IP Header =20 Byte(without options field),数据在IP层称为Datagram,分片称为Fragment。

(3)TCP Header = 20 Byte(without options field),数据在TCP层称为Stream,分段称为Segment(UDP中称为Message)。

(4)54个字节后为TCP数据负载部分(Data Portion),即应用层用户数据。

Ethernet Header以下的IP数据报最大传输单位为MTU(Maximum Transmission Unit,Effect of short board),对于大多数使用以太网的局域网来说,MTU=1500。

以太网帧头:

Ethernet_II的帧中各字段说明如下:
1.DMAC(DestinationMAC)是目的MAC地址。DMAC字段长度为6个字节,标识帧的接收者。
2.SMAC(SourceMAC)是源MAC地址。SMAC字段长度为6个字节,标识帧的发送者。
3.类型字段(Type)用于标识数据字段中包含的高层协议,该字段长度为2个字节。
类型字段取值为0x0800的帧代表IP协议帧;类型字段取值为0806的帧代表ARP协议帧。
0x8847 多协议标签交换(单播) MPLS:Multi-Protocol Label Switching <unicast>)
0x88CC 链接层发现协议(LLDP:Link Layer Discovery Protocol)
0x8863 以太网上的 PPP(发现阶段)(PPPoE:PPP Over Ethernet <Discovery Stage>)
4.数据字段(Data)是网络层数据,最小长度必须为46字节以保证帧长至少为64字节,数据字段的最大长度为1500字节。
5.循环冗余校验字段(FCS)提供了一种错误检测机制。该字段长度为4个字节。

 

IP头:

 

 

 

(1)版本 占4位,指IP协议的版本。通信双方使用的IP协议版本必须一致。广泛使用的IP协议版本号为4(即IPv4)。关于IPv6,还处于草案阶段。
(2)首部长度 占4位,可表示的最大十进制数值是15。请注意,这个字段所表示数的单位是32位字长(1个32位字长是4字节),因此,当IP的首部长度为1111时(即十进制的15),首部长度就达到60字节。当IP分组的首部长度不是4字节的整数倍时,必须利用最后的填充字段加以填充。因此数据部分永远在4字节的整数倍开始,这样在实现IP协议时较为方便。首部长度限制为60字节的缺点是有时可能不够用。但这样做是希望用户尽量减少开销。最常用的首部长度就是20字节(即首部长度为0101),这时不使用任何选项。
(3)区分服务 占8位,用来获得更好的服务。这个字段在旧标准中叫做服务类型,但实际上一直没有被使用过。1998年IETF把这个字段改名为区分服务DS(Differentiated Services)。只有在使用区分服务时,这个字段才起作用。
(4)总长度 总长度指首部和数据之和的长度,单位为字节。总长度字段为16位,因此数据报的最大长度为2^16-1=65535字节。
在IP层下面的每一种数据链路层都有自己的帧格式,其中包括帧格式中的数据字段的最大长度,这称为最大传送单元MTU(Maximum Transfer Unit)。当一个数据报封装成链路层的帧时,此数据报的总长度(即首部加上数据部分)一定不能超过下面的数据链路层的MTU值。
(5)标识(identification) 占16位。IP软件在存储器中维持一个计数器,每产生一个数据报,计数器就加1,并将此值赋给标识字段。但这个“标识”并不是序号,因为IP是无连接服务,数据报不存在按序接收的问题。当数据报由于长度超过网络的MTU而必须分片时,这个标识字段的值就被复制到所有的数据报的标识字段中。相同的标识字段的值使分片后的各数据报片最后能正确地重装成为原来的数据报。
(6)标志(flag) 占3位,但只有2位有意义。
● 标志字段中的最低位记为MF(More Fragment)。MF=1即表示后面“还有分片”的数据报。MF=0表示这已是若干数据报片中的最后一个。
● 标志字段中间的一位记为DF(Don’t Fragment),意思是“不能分片”。只有当DF=0时才允许分片。
(7)片偏移 占13位。片偏移指出:较长的分组在分片后,某片在原分组中的相对位置。也就是说,相对用户数据字段的起点,该片从何处开始。片偏移以8个字节为偏移单位。这就是说,除了最后一个分片,每个分片的长度一定是8字节(64位)的整数倍。
(8)生存时间 占8位,生存时间字段常用的的英文缩写是TTL(Time To Live),表明是数据报在网络中的寿命。由发出数据报的源点设置这个字段。其目的是防止无法交付的数据报无限制地在因特网中兜圈子,因而白白消耗网络资源。最初的设计是以秒作为TTL的单位。每经过一个路由器时,就把TTL减去数据报在路由器消耗掉的一段时间。若数据报在路由器消耗的时间小于1秒,就把TTL值减1。当TTL值为0时,就丢弃这个数据报。后来把TTL字段的功能改为“跳数限制”(但名称不变)。路由器在转发数据报之前就把TTL值减1.若TTL值减少到零,就丢弃这个数据报,不再转发。因此,TTL的单位不再是秒,而是跳数。TTL的意义是指明数据报在网络中至多可经过多少个路由器。显然,数据报在网络上经过的路由器的最大数值是255.若把TTL的初始值设为1,就表示这个数据报只能在本局域网中传送。
(9)协议 占8位,协议字段指出此数据报携带的数据是使用何种协议,以便使目的主机的IP层知道应将数据部分上交给哪个处理过程。
(10)首部检验和 占16位。这个字段只检验数据报的首部,但不包括数据部分。这是因为数据报每经过一个路由器,路由器都要重新计算一下首部检验和(一些字段,如生存时间、标志、片偏移等都可能发生变化)。不检验数据部分可减少计算的工作量。
(11)源地址 占32位。
(12)目的地址 占32

Options(可选项):是一个长度可变的字段。它是可选的。
可选项如下:
 松散源路由选择(loose source routing给出了一连串路由器接口的IP地址序列。数据包必须沿着IP地址序列传送,但是允许相继的2个地址之间可跳过多台路由器。
 严格源路由选择(strict source routing也给出了一连串路由器接口的IP地址序列,不同于松散源路由选择的是,数据包必须按照路由转发。如果下一条不在路由表,就将会发生错误。
 记录路由(Record Router当数据包离开时为每台路由器提供空间记录数据包的出站接口地址。
 时间戳(timestamp:时间戳相当于路由记录选项,这样数据包不仅可以知道自己到过那里。而且还可以记录到达的时间。
填充(padding)在可选项后面添加0来补足32位,主要是保证报头是32位的倍数

 

TCP数据包每次能够传输的最大数据分段为MSS(Maximum Segment Size)。

为了达到最佳的传输效能,在建立TCP连接时双方将协商MSS值——双方提供的MSS值中的最小值为这次连接的最大MSS值。

MSS往往基于MTU计算出来,通常 MSS = MTU-sizeof(IP Header)-sizeof(TCP Header)=1500-20-20=1460。

这样,数据经过本地TCP层分段后,交给本地IP层,在本地IP层就不需要分片了。但是在下一跳路由(Next Hop)的邻居路由器上可能发生IP分片!因为路由器的网卡的MTU可能小于需要转发的IP数据报的大小。这时候,在路由器上可能发生两种情况:

(1)如果源发送端设置了这个IP数据包可以分片(May Fragment,DF=0),路由器将IP数据报分片后转发。

(2)如果源发送端设置了这个IP数据报不可以分片(Don’t Fragment,DF=1),路由器将IP数据报丢弃,并发送ICMP分片错误消息给源发送端。

关于MTU的探测,参考《Path MTU discovery》。我们可以通过基于ICMP协议的ping命令来探测从本机出发到目标机器上路由上的MTU,详见下文。

TCP & MSS
下图是 TCP 报文格式:

 

 

 

    16位端口号:告知主机该报文段是来自哪里(源端口Source Port)以及传给哪个上层协议或应用程序(目的端口Destination Port)的。进行TCP通信时,客户端通常使用系统自动选择的临时端口号,而服务器则使用知名服务端口号(比如DNS协议对应端口53,HTTP协议对应80,这些端口号可在/etc/services文件中找到)。

        32位序号:一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。假设主机A和主机B进行TCP通信,A发送给B的第一个TCP报文段中,序号值被系统初始化为某个随机值ISN(Initial Sequence Number,初始序号值)。那么在该传输方向上(从A到B),后续的TCP报文段中序号值将被系统设置成ISN加上该报文段所携带数据的第一个字节在整个字节流中的偏移。例如,某个TCP报文段传送的数据是字节流中的第1025~2048字节,那么该报文段的序号值就是ISN+1025.另外一个传输方向(从B到A)的TCP报文段的序号值也具有相同的含义。

        32位确认号(acknowledgement number):用作对另一方发送来的TCP报文段的响应。其值是收到的TCP报文段的序号值加1。假设主机A和主机B进行TCP通信,那么A发送出的TCP报文段不仅携带自己的序号,而且包含对B发送来的TCP报文段的确认号。反之,B发送出的TCP报文段也同时携带自己的序号和对A发送来的报文段的确认号。

        4位头部长度(header length):标识该TCP头部有多少个32bit字(4字节)。因为4位最大能标识15,所以TCP头部最长是60字节。

        6位标志位包含如下几项:

        URG标志,表示紧急指针(urgent pointer)是否有效。

        ACK标志,表示确认号是否有效。我们称携带ACK标识的TCP报文段为确认报文段。

        PSH标志,提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间(如果应用程序不将接收

        到的数据读走,它们就会一直停留在TCP接收缓冲区中)。

         RST标志,表示要求对方重新建立连接。我们称携带RST标志的TCP报文段为复位报文段。

         SYN标志,表示请求建立一个连接。我们称携带SYN标志的TCP报文段为同步报文段。

         FIN标志,表示通知对方本端要关闭连接了。我们称携带FIN标志的TCP报文段为结束报文段。

       16位窗口大小(window size):是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口(Receiver Window,RWND)。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。此值告诉发送方,在没有收到我的确认时,你可以发送的数据的字节数最多是这个数值。

        16位校验和(TCP check sum):由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的一个重要保障。

        16位紧急指针(urgent pointer):是一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,不妨称之为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法。

        TCP头部选项:TCP头部的最后一个选项字段(options)是可变长的可选信息。这部分最多包含40字节,因为TCP头部最长是60字节(其中还包含前面讨论的20字节的固定部分)。典型的TCP头部选项结构如下图所示。

在基于传输层(TCP/UDP)的应用开发中,为了最后的程序优化,应避免端到端的任何一个节点上出现IP分片。TCP的MSS协商机制加上序列号确认机制,基本上能够保证数据的可靠传输。

UDP
下图是 UDP 报文格式:

 

 

 

UDP协议在IP协议的基础上,只增加了传输层的端口(Source Port+Destination Port)、UDP数据包长(Length = Header+Data)以及检验和(Checksum)。因此,基于UDP开发应用程序时,数据包需要结合IP分片情况考虑。对于以太局域网,往往取UDP数据包长Length<=MTU-sizeof(IP Header)=1480,故UDP数据负载量小于或等于1472(Length-UDP Header);对于公网,ipv4最小MTU为576,UDP数据负载量小于或等于548。

“向外”NAT在内网和公网之间提供了一个“不对称”桥的映射。“向外”NAT在默认情况下只允许向外的session穿越NAT:从外向内的的数据包都会被丢弃掉,除非NAT设备事先已经定义了这些从外向内的数据包是已存在的内网session的一部分。对于一方在LAN,一方在WAN的UDP通信,鉴于UDP通信不事先建立虚拟链路,NAT后面的LAN通信方需先发送消息给WAN通信方以洞穿NAT,然后才可以进行双向通信,这即是常提到的“UDP打洞(Hole Punching)”问题。

TCP连接百度过程解析
1.wireshark抓包
下文对百度的完整抓包建立在不使用缓存的基础上。如若主机存有百度站点的cookie和脱机缓存(Offline Cache),则不会再请求地址栏图标favicon.ico;请求/js/bdsug.js?v=1.0.3.0可能回应“HTTP/1.1 304 Not Modified”。可在浏览器打开百度首页后,Ctrl+F5强制刷新,不使用缓存,也可参考《浏览器清除缓存方法》。

以下为访问百度过程,wireshark抓包数据。对于直接通过Ethernet联网的机器,Wireshark Capture Filter为"host www.baidu.com";对于通过PPP over Ethernet(PPPoE)联网的机器,Wireshark Capture Filter为"pppoes and host www.baidu.com"。以下抓包示例直接通过Ethernet联网访问百度的过程。可点击下面的图片超链接下载pcap文件,使用wireshark软件打开查看。

为方便起见,以下将客户端(浏览器)简称为C,将服务器(百度后台)简称为S。

 

 

 

2.TCP三次握手建立连接
“http://”标识WWW访问协议为HTTP,根据规则,只有底层协议建立连接之后才能进行更高层协议的连接。在浏览器地址栏输入地址后按下回车键的瞬间,C建立与S(机器名为www.baidu.com,DNS解析出来的IP为220.181.6.175)的TCP 80连接(HTTP默认使用TCP 80端口)。

以下为三次握手建立TCP连接的数据包(Packet1-Packet3)。

/****************************************************************************************************

1  192.168.89.125:5672→220.181.6.175:80   TCP(协议) 62(以太网帧长)

     amqp > http [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1

2  220.181.6.175:80→192.168.89.125:5672 TCP 62

    http > amqp [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 SACK_PERM=1

3  192.168.89.125:5672→220.181.6.175:80   TCP 54

     amqp > http [ACK] Seq=1 Ack=1 Win=65535 Len=0

****************************************************************************************************/

三次握手建立TCP连接的流程如下:

    C(Browser)                                    S(www.baidu.com)

 1. CLOSED                                             LISTEN

 2. SYN-SENT    →<SEQ=0><CTL=SYN>              → SYN-RECEIVED

 3. ESTABLISHED← <SEQ=0><ACK=1><CTL=SYN,ACK> ← SYN-RECEIVED

 4. ESTABLISHED→ <SEQ=1><ACK=1><CTL=ACK>      → ESTABLISHED

 

2.1 三次握手的socket层执行逻辑
S调用socket的listen函数进入监听状态;C调用connect函数连接S:[SYN],S调用accept函数接受C的连接并发起与C方向上的连接:[SYN,ACK]。C发送[ACK]完成三次握手,connect函数返回;S收到C发送的[ACK]后,accept函数返回。

2.2 关于Seq和Ack
Seq即Sequence Number,为源端(source)的发送序列号;Ack即Acknowledgment Number,为目的端(destination)的接收确认序列号。在Wireshark Display Filter中,可使用tcp.seq或tcp.ack过滤。

在Packet1中,C:5672向S:80发送SYN握手包,Seq=0(relative sequence number);在Packet2中,S:80向C:5672发送ACK握手回应包,Ack=1(relative sequence number),同时发送SYN握手包,Seq=0(relative sequence number);在Packet3中,C:5672向S:80发送ACK握手回应包,Seq=1,Ack=1。

至此,Seq=1为C的ISN(Initial Sequence Number),后期某一时刻的Seq=ISN+累计发送量(cumulative sent);Ack=1为C的IAN(Initial Acknowledge Number),后期某一时刻的Ack=IAN+累计接收量(cumulative received)。对于S而言,Seq和Ack情同此理。

参考:《TCP Analyze Sequence Numbers》、《Understanding TCP Sequence and Acknowledgement Numbers》

3.TCP获取网站数据流程
连接建立后,下一步发送(“GET / HTTP/1.1”)请求(Request)HTML页面,这里“/”表示S的默认首页,“GET”为HTTP Request Method;“/”为Request-URI,这里为相对地址;HTTP/1.1表示使用的HTTP协议版本号为1.1。

以下为HTTP GET请求数据包(Packet4)。

/****************************************************************************************************

4  192.168.89.125:5672→220.181.6.175:80 HTTP 417

GET / HTTP/1.1

****************************************************************************************************/

HTTP GET报文长=417-54=363个字节,其中Next sequence number: 364(relative sequence number)表示,若在规定的时间内收到S响应Ack=364,表明该报文发送成功,可以发送下一个报文(Seq=364);否则重传(TCP Retransmitssion)。序列号确认机制是TCP可靠性传输的保障。

S(http)收到HTTP GET报文(共363个字节),向C(amqp)发送TCP确认报文(Packet5)。

/****************************************************************************************************

5  220.181.6.175:80→ 192.168.89.125:5672 TCP 60

http > amqp [ACK] Seq=1 Ack=364 Win=6432 Len=0

****************************************************************************************************/

这里Seq=1,为S的ISN,意为已发送过SYN。Packet2中,Ack=1为S的IAN。这里的Ack-IAN=364-1=363表示S已经从C接收到363个字节,即HTTP GET报文。同时,Ack=364也是S期待C发送的下一个TCP报文序列号(上面分析的Next sequence number)。

接下来,S向C发送Http Response,根据HTTP协议,先发响应头(Response Header),再发百度首页HTML文件。

Http Response Header报文(Packet6)如下。

/****************************************************************************************************

6  220.181.6.175:80→ 192.168.89.125:5672 TCP 465

[TCP segment of a reassembled PDU]

****************************************************************************************************/

其部分内容如下:

======================================

HTTP/1.1 200 OK

……

Content-Length: 2139

Content-Type: text/html;charset=gb2312

Content-Encoding: gzip

======================================

S响应C的“GET / HTTP/1.1”请求,先发送带[PSH]标识的411个字节的Http Response Header(Packet 6)。

TCP头部[PSH]标识置位,敦促C将缓存的数据推送给应用程序,即先处理Http Response Header,实际上是一种“截流”通知。相应C的socket调用send时在IPPROTO_TCP选项级别设置TCP_NODELAY为TRUE禁用Nagle算法可以“保留发送边界”,以防粘连。

尽管握手协商的MSS为1460,但服务器或者代理平衡服务器,每次发送过来的TCP数据最多只有1420个字节。可以使用ping -f -l size target_name命令向指定目标target_name发送指定字节量的ICMP报文,其中-l size指定发送缓冲区的大小;-f则表示在IP数据报中设置不分片DF(Don’t Fragment),这样便可探测出到目标路径上的MTU。

执行“ping -f -l 1452 www.baidu.com”的结果如下:

220.181.6.18的 Ping统计信息:

   数据包:已发送 = 4,已接收 = 4,丢失 = 0 (0%丢失)

执行“ping -f -l 1453 www.baidu.com”的结果如下:

需要拆分数据包但是设置 DF。

220.181.6.18的 Ping统计信息:

   数据包:已发送 = 4,已接收 = 0,丢失 = 4 (100%丢失)

从以上ping结果可知,在不分片时,从本机出发到百度的路由上能通过的最大数据量为1452,由此推算出MTU{local,baidu}=sizeof(IP Header)+ sizeof(ICMP Header)+sizeof(ICMP Data Portion)=20+8+1452=1480。

S调用socket的send函数发送2139个字节的Http Response Content(Packet 7、Packet 9),在TCP层将分解为两段(segment)后再发出去。

/****************************************************************************************************

7  220.181.6.175:80→ 192.168.89.125:5672 TCP 1474

[TCP segment of a reassembled PDU]

----------------------------------------------------------------------------------------------------

由“Content-Length: 2139”可知,HTML文件还有2139-(1474-54)=719个字节。但此时,C已经发送了确认报文(Packet8)。

/****************************************************************************************************

8  192.168.89.125:5672→  220.181.6.175:80 TCP 54

amqp > http [ACK] Seq=364 Ack=1832 Win=65535 Len=0

****************************************************************************************************/

Seq-ISN=364-1=363,表示C已经发出了363个字节,上边已经收到了S的确认。Ack-IAN=1832-1=(465-54)+(1474-54),表示C至此已经接收到S发来的1831个字节。

接下来,C收到HTML文件剩余的719个字节,报文(Packet9)如下。

/****************************************************************************************************

9  220.181.6.175:80→ 192.168.89.125:5672 HTTP  773

HTTP/1.1 200 OK

****************************************************************************************************/

至此,C收到S发送过来的全部HTTP响应报文,即百度首页HTML内容(text/html)。

Packet6、Packet7和Packet9的ACK都是364,这是因为这三个segment都是针对Packet4的TCP响应。S将百度首页HTML文件(一个完整的HTTP报文)按照MSS分段提交给TCP层。在Wireshark中可以看到Packet9的报文中有以下reassemble信息:

[Reassembled TCP segments (2555 bytes): #6(411),#7(1420),#9(719)]

[Frame: 6, payload: 0-410(411 bytes)]

[Frame: 7, payload: 411-1830(1420 bytes)]

[Frame: 9, payload: 1831-2549(719 bytes)]

C(amqp)接收到百度首页的HTML文件后,开始解析渲染。在解析过程中,发现页面中含有百度的logo资源baidu_logo.gif,并且需要bdsug.js脚本。

<img src="http://www.baidu.com/img/baidu_logo.gif" width="270" height="129" usemap="#mp">

{d.write('<script src=http://www.baidu.com/js/bdsug.js?v=1.0.3.0><//script>')}

于是上面那个连接(C:5672)继续向S请求logo图标资源,报文(Packet10)如下。

/****************************************************************************************************

10 192.168.89.125:5672→  220.181.6.175:80 HTTP 492

GET /img/baidu_logo.gif HTTP/1.1

****************************************************************************************************/

与此同时,C(jms)新建一个连接(TCP 5673)向S请求js脚本文件。报文(Packet11)如下。

/****************************************************************************************************

11 192.168.89.125:5673→  220.181.6.175:80 TCP 62

jms > http [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1

****************************************************************************************************/

(Packet12)Packet13、Packet14、Packet16和Packet17为对Packet10的TCP响应(它们的Ack=802),在逻辑上它们是一个完整的TCP报文。其Http Response Content为图片文件baidu_logo.gif。我们在Wireshark中可以看到Packet17的报文中有以下reassemble信息:

[Reassembled TCP segments (1801 bytes): #13(312),#14(1420),#16(28) ,#17(41)]

[Frame: 13, payload: 0-311(312 bytes)]

[Frame: 14, payload: 312-1731(1420 bytes)]

[Frame: 16, payload: 1732-1759(28 bytes)]

[Frame: 17, payload: 1760-1800(41 bytes)]

Packet11-Packet19-Packet20完成新连接的三次握手。然后,C(jms)发送“GET /js/bdsug.js?v=1.0.3.0 HTTP/1.1”报文(Packet21),以获取bdsug.js脚本文件。

/****************************************************************************************************

21 192.168.89.125:5673→  220.181.6.175:80 HTTP 465

GET /js/bdsug.js?v=1.0.3.0 HTTP/1.1

****************************************************************************************************/

(Packet22)Packet23、Packet24、Packet26和Packet27为对Packet21的TCP响应(它们的Ack=412),在逻辑上它们是一个完整的TCP报文。其Http Response Content为脚本文件bdsug.js。我们在Wireshark中可以看到Packet27的报文中有以下reassemble信息:

[Reassembled TCP segments (3897 bytes): #23(310),#24(1420),#26(1420) ,#27(747)]

[Frame: 23, payload: 0-309(310 bytes)]

[Frame: 24, payload: 310-1729(1420 bytes)]

[Frame: 26, payload: 1730-3149(1420 bytes)]

[Frame: 27, payload: 3150-3896(747 bytes)]

通常,浏览器会自动的搜索网站的根目录,只要它发现了favicon.ico这个文件,就把它下载下来作为网站地址栏图标。于是,C(amqp)还将发起“GET /favicon.ico HTTP/1.1”请求网站地址栏图标,见报文Packet29。

4.TCP四次挥手关闭连接
经Packet28确认收到了完整的japplication/javascript文件后,链路1(本地端口5673)使命结束,S关闭该链路,进入四次挥手关闭双向连接。

(Packet30)Packet31和Packet32为对Packet29的TCP响应(它们的Ack=1201)。经Packet33确认收到了完整的image/x-icon文件后,链路2(本地端口5672)使命结束,S关闭该链路,进入四次挥手关闭双向连接。

   为什么握手是三次,而挥手是四次呢?这是因为握手时,服务器往往在答应建立连接时,也建立与客户端的连接,即所谓的双向连接。所以,在Packet2中,服务器将ACK和SYN打包发出。挥手,即关闭连接,往往只是表明挥手方不再发送数据(无数据可发),而接收通道依然有效(依然可以接受数据)。当对方也挥手时,则表明对方也无数据可发了,此时双向连接真正关闭。

 

参考:

《浏览器/网页工作原理》《What really happens when you navigate to a URL》

《HTTP通信过程分析》

《究竟什么是HTTP连接》

《一次完整的HTTP通信步骤》

《SOCKET与TCP/IP与HTTP的关系》

《TCP连接、Http连接与Socket连接》

《TCP传输协议抓包经验》
————————————————
版权声明:本文为CSDN博主「弦苦」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/phunxm/java/article/details/5836034

posted @ 2020-04-09 17:25  繁星如雨  阅读(1967)  评论(0编辑  收藏  举报