not a better man

前端技术

HTTP2协议之TCP协议1 -学习笔记二

上一篇文章说起http1.1协议并没有效利用tcp协议,而且tcp协议的连接耗时,接下来,我们来瞧一瞧tcp协议。上图是建立tcp协议的过程以及传输文件的过程。这篇文章带领大家使用抓包工具来分析tcp协议

下载抓包分析工具wireshark

wireshark是一款强大的抓包分析工具,下载地址自行google,度娘。使用教程自行google,度娘。启动wireshark 如下所示

TCP协议的包头构成

我们上面的一片文章说了osi 七层协议模型,从底由上分别为物理层,数据链路层, 网络层,传输层 ,会话层,表示层 ,应用层,应用层。TCp/IP协议剔除了其中会话层,表示层 ,变成了物理层,数据链路层, 网络层,传输层 ,应用层。如下图所示

osi模型和tcp协议模型

我们使用telnet 来请求 http://www.alonehero.com  然后使用wireshark来捕获tcp包视频如下

抓包如下图

我们可以看到31,32,33 建立了三次握手协议,第714个包是telnet 向www.alonehero.com 发送www的请求。我们打开第714个包,包内容如下

看图中弟二部分,wireshark能够分析从数据链路层-》网络层(IPv4)》传输层 以及以上的协议。TCP/IP协议的分层很清楚。现在我们不分析数据链路层和网络层的数据内容,我们只分析第714个包的传输层协议,如下图所示

我们结合tcp包头的结构图来一一对比

从图中看出 源端口号是:57982

目标端口是:80

序列号占4个字节是59af666d

窗口大小是 4128

标志位6位,含义分别如下:

URG:紧急指针有效

ACK:确认序号有效

PSH:接收方尽快将这个报文段交给应用层

 RST:重建连接

SYN:同步序号用来发起一个连接

FIN:发端完成发送任务

现在我们初步了解到了tcp包头的结构了,但是我们无法从tcp报头中得知每个tcp传输的数据的大小,tcp包没有指定。我们怎么确定每个tcp包承载的数据呢,我可以从IP数据包的包头中去分析,然后结合tcp包头,就能分析每个tcp包能承载多少数据。IP数据包的结构如下

ip数据包结构

我们从ip数据包中发现包裹总长度为16个字节,那么每个ip数据包最大只能有64KB大小,我们减去ip数据包的包头,然后减去tcp包的包头,就剩下tcp 承载的数据的大小,总之会小于64KB。

为什么tcp连接成功的最少次数是3次握手呢

为什么tcp连接成功最少需要来回发送三个tcp数据包呢?不是两个,不是四个。首先我们要明确一个事实,tcp通信是保证双向的,然后保证是可靠的。就是a能够保证接受到b发送过来的包,b也能确定自己发送的包a接受到了,反之也一样。在这种情况下,连接的成功至少需要三个tcp包,我们可以从tcp包的结构去考虑。三次握手已经是最优的了。

我从下面这张图来开始阐述为什么至少需要三次握手

三次握手的说明

首先我们要知道是双向通信,双方都要保证自己的包发出去,自己知道自己的包对方接受成功。那么怎么知道自己的包对方接受成功呢 。我们可以通过Sequence Numer 和Acknowgement Number来确认。

上图中  A 请求建立连接。

1.  A 生成一个序列号为 2000 ,应答序列号为0 ,当B接受到该tcp包,并结合标识位 SYN 知道A要建立连接,之前相互之间没有联系,或联系已断开。但是这个时候,A还不知道自己的包,B是否能够接受到。

2.B 接受到A发送过来的包之后,自己生成一个序列号3000,然后将Ack的数字 = A的SYN +1 =2001,并将标识位SYN设置为1,自己想,如果A接受到我的包,检查我的Ack值就知道自己的包,我已经成功接受到,检查我的syn序列号和syn标识位,知道我也想建立连接,给A发送数据。 B想好之后把该包发送出去。但b无法知道自己包A是否成功接受

3 A接受到B发送过来的包,检查一下Ack值,是在自己的syn上加1了,表明自己的包发送成功。包中还含有SyN标识位为1,那么之前没有建立过连接啊,b发送过来的包,我使用这个syn加1,表明我签收成功啊。以后,你来往,就用对方的syn序列值加一,变成自己的ack数值,保证自己已成功接收到对方的数据包。这样能提高效率,也能确定包的成功接收。 A马上发送一个tcp包过去,将自己的syn序列值设为2001,将ack序列值设为对方的syn+1 =3001 并将标识位中ack 设为1。说我已成功接收到你的包,我们的双向通信建立成功了。

此后如果a发送数据,就将自己的数据使用syn值加1编号,发送过去,收到对方的包之后,如果发现ack=自己刚发出去syn+1 ,就知道自己的之前的包,对方接收成功了,自己该发syn+1的数据过去了。双方都设置了一个定时器,如果在定时器的时间内没有接收到包,再次发送相应的数据包。

从上面的描述,我们清楚了,在不可靠的信道上,保证双方可靠的传输至少需要3次握手,不能再少了。

此外也知道建立tcp连接的代价是很高的,那么tcp承载的数据,能多路复用的话,最好多路复用,提高每个tcp数据包有效利用率。http2 协议中增加的分帧和stream保证了多路复用的可行性,尽量提高每个数据包的大小,当然无法超过64KB.

TCP的队首阻塞问题

TCP包的按序接受,丢包重发保证了上层的应用程序,在处理数据的过程中,并不需要考虑数据的分组与重排,使应用程序简单化,但是TCP包这些特性会有队首阻塞的问题,每一个包按照序列号的顺序发送给接受端,但是,一个序列号在前的包后到达接收端,或丢失,序列号在后的包先到达接收端,会被保存在接收端的TCP缓冲区,等待丢失或后到达的包(序列号在前)到达之后,应用程序才能处理数据,这样会有一定的延迟,有些延迟不可预测,上述现象是TCP的队首阻塞,不可避免,但是并不是所有的应用程序需要数据的完整性和按序交互.TCP的队首阻塞问题是该协议的弱势,但是TCP协议栈都写入到操作系统内核中,更新,修改成本高。估计慢慢的会有新的协议出现,如谷歌的QUIC协议。

接下来,会描述TCP协议的其他特性。

发表评论