三次握手
提到 tcp 协议,每个人大概都能想到建立 tcp 连接需要三次握手。初次接触,很自然地会提出一个疑问:为什么需要三次握手?两次不行吗?
要回答这个问题之前,我们先回顾一下什么 tcp。tcp 协议是传输层协议,为上层协议如 http、ftp 等提供双向的、可靠的、按序的字节流逻辑信道。tcp 建立连接的三次握手过程如下:
client server
SYN
------------------------------------->
SYN+ACK
<-------------------------------------
ACK
------------------------------------->
先明确一下三次握手,每次握手都在做什么:
1、c 端向 s 端发送 syn
“我要和你通信咯。我发送的 packet 的初始序号从 x 开始。一定要从 x 序号开始收我发的 packet 啊,这样才能保证信息重组后不乱序呀。你如果收到了,就告诉你收到了信息。并且把你要发送的 packet 的初始序号 y 发给我,我好确认你给我发的 packet”
2、s 端向 c 端发送 ack+syn
"我收到你的信息了。我会从序号 x 开始确认你发的 packet。这是我将要发你的 packet 的初始序号。等你确认收到我的消息时,我们就可通信啦"
3、c 端向 s 端发送 ack
"我收到了你的初始序号了。现在我们可以可靠地进行通信了"
用 linux 下的 dump 命令查看一下握手过程
监听网卡
➜ ~ sudo tcpdump host www.zhihu.com
curl 请求
➜ ~ curl -I www.zhihu.com
HTTP/1.1 301 Moved Permanently
Date: Sat, 28 Oct 2017 01:43:25 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Set-Cookie: aliyungf_tc=AQAAAM2jCXsmxwAAk6P53EBJXABbb44Z; Path=/; HttpOnly
Location: https://www.zhihu.com/
X-Req-ID: 13F2DBE59F3E0BD
Server: ZWS
Vary: Accept-Encoding
dump 输出
09:43:24.475574 IP waydembp.63532 > 118.178.213.186.http: Flags [SEW], seq 609956406, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 222104353 ecr 0,sackOK,eol], length 0
09:43:24.559886 IP 118.178.213.186.http > waydembp.63532: Flags [S.E], seq 1238093818, ack 609956407, win 14600, options [mss 1444,nop,nop,sackOK,nop,wscale 7], length 0
09:43:24.559954 IP waydembp.63532 > 118.178.213.186.http: Flags [.], ack 1, win 8192, length 0
09:43:24.560131 IP waydembp.63532 > 118.178.213.186.http: Flags [P.], seq 1:79, ack 1, win 8192, length 78: HTTP: HEAD / HTTP/1.1
09:43:24.605720 IP 118.178.213.186.http > waydembp.63532: Flags [.], ack 79, win 115, length 0
09:43:24.684824 IP 118.178.213.186.http > waydembp.63532: Flags [P.], seq 1:315, ack 79, win 115, length 314: HTTP: HTTP/1.1 301 Moved Permanently
09:43:24.684909 IP waydembp.63532 > 118.178.213.186.http: Flags [.], ack 315, win 8182, length 0
09:43:24.685170 IP waydembp.63532 > 118.178.213.186.http: Flags [F.], seq 79, ack 315, win 8192, length 0
09:43:24.729360 IP 118.178.213.186.http > waydembp.63532: Flags [F.], seq 315, ack 80, win 115, length 0
09:43:24.729415 IP waydembp.63532 > 118.178.213.186.http: Flags [.], ack 316, win 8192, length 0
前三条记录体现了握手过程。
关于初始 init seq num 可以看 [rfc-761 page27]
但是从输出看,我有一个疑惑:s 端的 init seq 为 1238093818(line 2),但是 c 端请求数据却是从 seq 1 (line 4)开始?
从这篇博文来看,第三行之后的 seq num 应该都是 relative seq num。就是第三行之后的 seq num 都是相对于 init seq 的偏移量。所以就可以理解为什么第四行编号从 1 开始。