- 浏览: 1154345 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
MyEyeOfJava:
产生问题的主要原因:1.方洪波与南枫公司的直接主管李琼在合作共 ...
人力资源管理案例-左右为难的经理 -
吾名长弓:
学习了,作为一个管理新手,从文章里学到了很多东西,感谢 ...
2018新年管理感言 -
MyEyeOfJava:
非常不错,看过很多文章,说到管理者必然不能抛弃技术,我的主张是 ...
IT行业技术部门人员架构设计 -
小灯笼:
JMeter测试从入门到精通网盘地址:https://pan. ...
LR与Jmeter相关资料 -
flying6071:
“(2)CERT.SF:这是对摘要的签名文件。对前一步生成的M ...
Android签名与认证详细分析之一(CERT.RSA剖析)
TCP通信流程解析
http://blog.csdn.net/phunxm/article/details/5836034
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连接 》
http://blog.csdn.net/phunxm/article/details/5836034
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连接 》
发表评论
-
python3常见操作
2019-06-03 11:07 648布尔操作,是或者否: Opera ... -
K8S
2019-05-31 09:41 601最近用自己的mac折腾了2天K8S,单机环境终于建设起来了。 ... -
接口与场景性能压测平台的实现
2019-01-11 13:37 10811.技术架构:reactjs+spring+mysql+in ... -
java虚拟机内存监控工具jps,jinfo,Jstack,jstat,jmap,jhat使用
2017-07-04 09:39 854这里将介绍几款sun hotspot jvm 自带的监控工 ... -
sort命令
2017-01-15 11:56 587-rw------- 1 eamon staff ... -
Groovy-mac环境搭建
2017-01-14 20:12 723Groovy官网上写明:可以使用命令行的方式,用SDKMA ... -
grafana开源报表工具
2016-12-23 14:54 2675服务器端性能监控,数据报表一个比较好的开源报表工具,Gra ... -
简单脚本实现百度搜索框1s1次变更值
2016-09-16 16:10 521可改造为秒杀脚本。 var i = 0; functio ... -
解决jenkins下使用HTML Publisher插件后查看html报告显示不正常
2016-09-13 10:37 3285在jenkins后使用html publisher查看ht ... -
2015年度阿里个人奖项
2016-09-08 13:35 1812从帅气的Coser转身变成华丽的小天鹅———————— ... -
Linux下录制视频
2016-08-11 18:09 878在Linux上怎么录制终端操作 录制一个终端操作可能是一个帮助 ... -
Discuz+centos7搭建指南
2016-04-13 11:12 14161.参考腾讯云的安装文档:http://bbs.qcloud ... -
使用charles抓取ios手机https内容
2016-01-27 16:21 2508按照网络上大多数帖子来做,你肯定会遇到问题的,我也是 ... -
TraceView工具的使用
2015-10-21 15:56 4206TraceView使用经验 在对手机淘宝性 ... -
Burp Suite使用介绍(一)
2015-08-12 10:01 2617Getting Started Burp Suite ... -
DroidBox简介
2015-08-12 09:56 1889目前Android系统最大的问题是什么?安全,这也是Andr ... -
Drozer – Android APP安全评估工具(附测试案例)
2015-08-12 09:53 3005Drozer原名mercury,是一款不错的Android ... -
[hookme]TCP代理工具只能在windows上使用
2015-08-12 09:50 1587HookME可在TCP通信中hook进程和API,从而 ... -
Git Stash用法
2015-08-04 11:37 1105最近在使用Git管理项目 ... -
mac内容如何更改maven指定的java版本
2015-07-21 10:15 1618原文地址 http://www.geeekr.com/fix- ...
相关推荐
本教程将详细讲解如何通过OPC_OPC转MODBUS-TCP转换,以及OPC_MODBUS协议转换的相关知识。 首先,理解OPC与MODBUS协议的基本概念: 1. OPC:OPC是为了解决不同厂商的工业自动化设备之间数据交换的标准接口。它包括...
TcpComm-tcp转串口的实现通常涉及到以下步骤和知识点: 1. **建立TCP连接**:首先,需要创建一个TCP客户端或服务器来监听或连接到指定的IP地址和端口。这可以通过使用标准的socket编程接口实现,如在Python中的...
本文将详细讲解这一过程及其相关知识点。 MOXA是一家知名的工业网络设备制造商,其产品广泛应用于各种自动化系统中。其中,Nport5410是一款功能强大的串口服务器,能够将多个RS485或RS232串口设备转换为TCP/IP网络...
本项目提供的"网络(TCPServer)转串口(UART)(源码)"是用C#语言实现的,它允许通过TCP服务器与串口进行数据交互,这在需要远程控制硬件设备或者整合网络和本地串口资源的场景下非常有用。下面将详细介绍这个项目...
标题中的"TCP.rar_28335 IP TCP_tcp 通信"可能是指一个关于TCP/IP通信的资源包,其中包含了一些与TCP相关的代码或文档,文件编号可能是"28335"。描述中提到"已经验证过了,可以编译通过",这表明这是一个实际操作过...
TCP 实习内容及相关知识内容 TCP(Transmission Control Protocol,传输控制协议)是 OSI 模型中的传输层协议之一,它提供了可靠的、面向连接的数据传输服务。在本文中,我们将详细介绍 TCP 的基础知识、相关概念、...
TCP/IP协议是互联网的核心协议,它定义了网络设备如何交换数据以及数据如何被格式化以进行传输。在VB.NET环境中,开发...这对于构建网络应用程序,如聊天软件、文件传输服务或者在线游戏等,都是非常重要的基础知识。
本篇将深入探讨这些知识点。 1. **TCP**:TCP是一种面向连接的、可靠的传输协议,它确保了数据的顺序传输和错误检测。通过三次握手建立连接,四次挥手断开连接,确保了数据传输的完整性。在物联网应用中,TCP常用于...
漫话IP:TCP_IP基础知识读本
### TCP/IP协议知识点总结与面试 #### 一、TCP/IP整体认知 TCP/IP协议栈是互联网的核心协议之一,由四个主要层次组成:应用层、传输层、网络层和链路层。TCP/IP协议栈不仅定义了如何封装和解封装数据,还定义了...
TCP 协议基础知识及图示 TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层协议。它是 Internet 协议族中的一个核心协议,用于保证数据的可靠传输。 TCP 协议基础...
总的来说,这个项目提供了使用C#实现MODBUS TCP客户端的实践,可以帮助开发者学习如何与MODBUS设备进行有效通信,以及如何处理相关的网络和协议问题。通过深入理解和实践这些知识点,开发者可以创建出高效、可靠的...
这个压缩包可能包含了源代码、说明文档和其他相关资源,用于帮助学习者理解如何在VB环境中构建TCP服务器和客户端应用程序。 描述中的"用VB实现客户——服务器(TCP/IP)编程实例"揭示了这是一个实际操作的教程,它...
知识点: 1. Modbus协议是一种开放式的工业协议,支持传统的RS-232、RS-422、RS-485和以太网设备。 2. ModbusTCP/RTU网关可以实现ModbusRTU协议的串口设备与以太网的无缝连接。 3. uIP协议栈是一个轻量级的TCP/IP...
LabVIEW,全称Laboratory Virtual Instrument Engineering Workbench,是一款由美国国家仪器公司(NI)开发的图形化编程环境,主要用于创建虚拟仪器...对于需要进行TCP/IP通信的项目,熟练掌握这些知识点是至关重要的。
在易语言中,实现TCP通信通常涉及到以下几个关键知识点: 1. **TCP连接**:在TCP通信中,首先需要建立一个连接。这通常通过`创建套接字`命令来实现,创建一个套接字对象,然后使用`连接到服务器`命令与指定的远程...
"TCP/IP常见面试知识点" TCP/IP 协议簇是计算机网络中最为重要的一部分,理解 TCP/IP 协议的工作机理和每个层的作用对于程序员和网络管理员来说都是必备的基础素养。本文将从 TCP/IP 模型、数据链路层、网络层、...
首先,理解Modbus TCP的基础知识至关重要。Modbus是一种串行通信协议,由Modicon公司在1979年推出,主要用于工业自动化设备。后来,为了适应网络环境,Modbus TCP被创建,它将原始的Modbus协议与TCP/IP网络协议栈相...
最后,"MODBUS_TCP_协议设置.tpc"文件可能是PLC的通信配置文件,其中详细列出了与MODBUS TCP相关的网络配置和设备信息。这些配置包括MODBUS通信的端口号(默认为502)、连接超时设置、重试次数等。 综上所述,这个...
在IT行业中,网络通信是...总的来说,理解TCP和UDP的工作原理以及如何使用测试工具进行评估和调试,对于任何IT专业人员来说都是必要的技能,无论是在开发网络应用还是维护网络基础设施时,这些知识都能带来显著的帮助。