`
sabolasi
  • 浏览: 908808 次
文章分类
社区版块
存档分类
最新评论

TCP通信流程解析

 
阅读更多

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/IP 数据包,结合 TCP 协议分析 HTTP 通信的基本流程。

MTU MSS

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

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

1 Ethernet Header = 14 Byte = Dst Physical Address 6 Byte + Src Physical Address 6 Byte + Type 2 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

TCP 数据包每次能够传输的最大数据分段为 MSS 为了达到最佳的传输效能,在建立 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 UDP

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

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 数据负载量小于或等于 536

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

TCP 连接百度过程解析

下文对百度的完整抓包建立在不使用 缓存的基础上。如若主机存有百度站点的 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

1 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

3-Way Handshake for Connection Synchronization

三次握手的 socket 层执行逻辑

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

关于 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 Initial Sequence Number ISN ),后期某一时刻的 Seq=ISN+ 累计发送量 (cumulative sent) Ack=1 C Initial Acknowledge Number IAN ),后期某一时刻的 Ack=IAN+ 累计接收量 (cumulative received) 。对于 S 而言, Seq Ack 情同此理。

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

2 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 数据报中设置不分片( 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 5 673 )向 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

3 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连接

分享到:
评论

相关推荐

    wireshark抓包tcp连接百度通信过程

    《TCP通信流程解析》博文中TCP连接百度抓包文件,使用wireshark打开。

    VLAN间数据包通信过程详解

    最近实习,在学习cisco路由器和交换机相关知识。这篇PPT是我自己根据所学知识,并上网查阅...主要讲述了同一VLAN间数据包传输过程和不同VLAN间数据包如何传输。涉及到三层交换机相关知识。因为初学,有不足地方请指正。

    TCP/IP协议详解(完整目录版)

    TCP/IP协议详解 完整目录 第一部分 TCP/IP基础 第1章 开放式通信模型简介 1 1.1 开放式网络的发展 1 1.1.1 通信处理层次化 2 1.1.2 OSI参考模型 3 1.1.3 模型的使用 5 1.2 TCP/IP参考模型 7 1.3 小结 7 第2章 TCP/IP...

    基于Python的ModbusTCP客户端实现详解

    Modbus Poll和Modbus Slave是两款非常流行的Modbus设备仿真软件,支持Modbus RTU/ASCII和Modbus TCP/IP协议 ,经常用于测试和调试Modbus设备,观察Modbus通信过程中的各种报文。 当用于支持Modbus RTU/ASCII协议时,...

    TCP通信代码.zip

    完整的TCP传输过程,该部分代码解决了IP解析,端口被占用问题。可以供初学者进行Java的学习,以便更好的了解Java端到端之间的连接,数据流的流动。

    TCP/IP详解

    6.7 名字服务解析过程 52 6.7.1 递归查询 52 6.7.2 叠代查询 52 6.8 高速缓存 52 6.9 反向解析(Pointer)查询 52 6.10 DNS安全 52 6.11 资源记录 53 6.12 小结 54 第7章 WINS 55 7.1 NetBIOS 55 7.2 NetBIOS名字解析 ...

    Qt设备状态检测系统源代码串口 网络TCP UDPModbus通信协议带有报警声音详细注释 设备状态检测源代码支持串口网口Tcp

    Qt设备状态检测系统源代码串口 网络TCP UDPModbus通信协议带有报警声音详细注释 设备状态检测源代码支持串口网口TcpUdp播放音频LED显示采用modbus协议 提供,提供详细注释,提供设计文档 使用说明介绍 1.功能介绍: ...

    TCP-IP技术大全

    本书内容十分丰富,几乎涵盖了有关TCP/IP的各个方面,包括开放式通信模型、TCP/IP通信模型、IP网络中的命名和寻址机制、地址解析及反向地址解析协议、DNS域字服务器、WINS、地址发现协议、IPv6、IP网络中的路由协议...

    TCP/IP教程TCP/IP基础

    6.7 名字服务解析过程 52 6.7.1 递归查询 52 6.7.2 叠代查询 52 6.8 高速缓存 52 6.9 反向解析(Pointer)查询 52 6.10 DNS安全 52 6.11 资源记录 53 6.12 小结 54 第7章 WINS 55 7.1 NetBIOS 55 7.2 NetBIOS名字解析 ...

    TCP三次握手四次挥手的过程详解.md

    TCP三次握手四次挥手的过程详解.mdTCP三次握手四次挥手的过程详解.mdTCP三次握手四次挥手的过程详解.md

    TCP/IP技术大全

    6.7 名字服务解析过程 52 6.7.1 递归查询 52 6.7.2 叠代查询 52 6.8 高速缓存 52 6.9 反向解析(Pointer)查询 52 6.10 DNS安全 52 6.11 资源记录 53 6.12 小结 54 第7章 WINS 55 7.1 NetBIOS 55 7.2 NetBIOS名字解析 ...

    JetLinks物联网基础平台-使用TCP服务网关接入设备

    本文档使用Packet Sender工具模拟tcp客户端接入平台。 创建协议 请参考创建协议 创建设备型号 ... ... i.... ii....注意:本文档使用javascript自定义脚本的方式解析消息。 自定义脚本: var BytesUtils =

    Qt 开发之Modbus通信

    简单的Modbus通信,主要是用于简单了解Modbus通信的编程流程,以及Modbus通信signed和long DC BA通信数据的转化原理,内含源码,操作手册,应用程序。如有错误或者不到指出,包括注释理解的缺陷,请联系我指正,谢谢...

Global site tag (gtag.js) - Google Analytics