learn-tech/专栏/全解网络协议/14我那不为人知的秘密是什么-TCP(二).md
2024-10-16 06:37:41 +08:00

49 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

因收到Google相关通知网站将会择期关闭。相关通知内容
14 我那不为人知的秘密是什么 - TCP
我们之前学习IP的时候就是把IP的header彻底的分析了一番是不是既然我已经给自己挖了这个坑就一定要把这个坑填好我们现在来一起学习一下TCP的header。
TCP Header
上图就是一个TCP Header的文件。我们还是一点点的来分析。 Source Port源端口源TCP的用户 Destination Port目标端口目标TCP 用户的端口 Sequence Number序列号: 第一个数据字节的序列号SYN标志除外。如果设置了SYN则此字段包含初始序列号ISN。下面的例子很严重依赖这个序列号你想不明白都难。 Acknowledgment Number确认号: 包含TCP期望接收的下一个数据的序列号。 Data Offset数据偏移: 头中32位字的数量。 Reserved保留: 为以后保留使用。 Flags标识:这里有几种数值,我在下面扩展讲。 Window 窗口大小TCP流量控制的一个手段用来告诉对端TCP缓冲区还能容纳多少字节。 CheckSum校验: 由发送方填充接收方对报文段执行CRC算法以检验TCP报文段在传输中是否损坏。 Urgent Pointer紧急指针一个正的偏移量它和序号段的值相加表示最后一个紧急数据的下一字节的序号接收方可以通过此来知道有多少紧急的数据用过来。 Options + Padding:可选和填充项。
Flags
CWR拥塞窗口减少标志 ECE: ECN响应标志被用来在TCP3次握手时表明一个TCP端是具备ECN功能的 URG: 紧急标志 ACK: 确认标志,还记得三次握手吗 RST: Reset连接看林志玲内衣的例子我相信你一辈子都不会忘 SYN: 同步序列号 FIN: 发送方没有数据了,想想四次分手
我们来看一下这个图这个还是用wireshark抓下来的包你可以从图上清楚的看到我们上面讲的TCP header都在实际的包中。
那背后无形的大手
我们现在开始进行更深层次的讨论那就是TCP如何提供可靠的传输呢简单的说就是使用序列号和确认号。
到目前为止我们了解了三次握手以及握手背后的本质。其中包含SYNSYN-ACK和ACK。然后建立连接开始通信。我们现在就来看一下通信是怎么实现的比如说下面这个图
客户端要从服务器获得这个精美的图片但是图片太大不可能一次性的发送服务器要做的就是把它分割成几个部分。还记得我们之前看的那个Segment部分里的Payload吗这个图片就可以放到那个部分。这个payload最大可以使用的容量是1460 bytes所以你不能放超过这个限制的数据。我们之前的那个Segment里面是不是还有序列号和确认号。因为我们还没有发送或者接收任何的数据。所以我们可以给这个序列号为1。确认号也是1。序列号代表我发送的数据的第一个字节数。我还没有发送任何数据所以最开始是1。我把这个图片分成固定的大小比如说每一小部分就是250 bytes那么我们上面说的最大容量是1460 bytes。所以我们可以在这个payload里面放五个图片分割之后的部分对不对。那就是1250 bytes然后把这个Segment包装到Packet里然后从服务器端发送到客户端。 然后客户端收到这个Packet是不是要开始剖洋葱把Packet打开从Segment里面取出这5个分割的图片部分然后组装这个图片。客户端这个时候已经收到了从1到1250字节的数据对不对。然后该到客户端操作了。
客户端也要开始构建自己的Segment了这个Segment要确认收到了刚刚的1250 bytes的图片数据。这里要注意客户端发送的这个序列号还是1为什么呢因为客户端还没有发送任何的数据给服务器对不对所以序列号还是1。客户端可以发数据也可以不发数据我们这里比较重要的是什么是这个确认号现在的确认号是1251。聪明的你会不会问为什么是1251不是1250这里你要记住这个确认号要永远比你接收到的最大的字节数加1因为客户端收到了1-1250之所以要发送回1251是为了告诉服务器你现在可以发送1251这个字节后面的数据了。然后把这个Segment封装到Packet里发送给服务器。
服务器收到之后打开这个包裹看到消息说好的你已经收到了1-1250我现在开始发送1251是不是又可以放5个图片的部分到payload然后把序列号改成1251确认号还是1然后走你再发送给客户端。
客户端这个时候还是重复上面的动作拆开包裹取出照片组合收到的照片部分。也许你还很年轻但是在大概1992年的时候下载图片其实就是这样你会发现没有下载完的图片会一点点的展示有的部分有有的没有。当然我这里只是给你掰开了细细的讲。让你可以明白的更加透彻。这个时候客户端又要重新构建了你自己想一下这个确认号和序列号应该是什么是不是序列号还是1因为还是没有数据要发送给服务器然后确认号这个时候是2501了吧。因为客户端已经收到了2500 bytes了。需要告诉服务器的是我要开始接收2501以后的字节了。
然后这个球又到了服务器这边了我就不再讲的那么细致了简写一下就是现在的新Segment是不是序列号变成2501了确认号还是1。世界不可能永远那么美好。这个时候当服务器把这个消息发给客户端的时候由于某种原因可能是哥斯拉入侵。这个消息弄丢了。世界末日了吗当然不会。这个时候是TCP展现真正技术的时候了。我们来看一下TCP是如何解决这个问题的。
现在数据丢了但是服务器还不知道这个消息是不是丢了因为它只是发出去了一个消息后面什么都不知道了。当然客户端也不知道发生了什么。因为客户端什么都没有收到。当然我们这里是放慢了100倍的来讲解实际上在现实中如果一个packet丢失了服务器那边可能已经开始发送新的Packet了Anyway我们继续我们这边的慢动作。服务器那边因为不知道发生了什么又继续发了一个新的Packet序列号是3751。当客户端收到这个包裹的时候会放到对应的位置但是问题来了。是不是缺少2501-3750这个部分。这个时候客户端会发送一个特殊的Segment在FLAG部分发送的是SACK也就是Selective ACK, 确认号是5001 2501-3750。这说明什么意思呢这是告诉服务端我收到了5000但是2501-3750我没有收到。所以我需要5001之后的部分以及2501-3750这部分。客户端把这Segment打包好后发给服务器。
服务器收到了之后呢自然表示很惊讶对不对但是作为信誉极好的卖家来说既然快递丢了我已经重新发送于是又重新构建了一个新的Segment包含2501-3750这部分的数据发送给客户端。不可能总是丢同一个包裹吗这次就很正常的发送给了客户端。客户端收到了之后就又开始拆包组装。客户端知道应该要放到哪里因为有序列号告诉客户端这个数据要放到哪里。然后再发送会ACK的Segment告诉服务器我现在需要5001以后的数据。然后发给服务器。
这个时候服务器把最后的部分都发送给了客户端客户端也完美的拼接好了照片但是客户端不知道已经完全发送完毕了。客户端会继续的发送说我需要6251之后的数据。但是服务器端是知道数据已经全部发完了所以服务器会发送一个Segment其中的Flag部分是FIN。还记得这个吗这个是要开始分手的标志了。当然这个时候Payload上什么数据都没有。然后就开始了分手流程。完成了四次分手。这个会话就结束了。当然客户端会给服务端一个五星好评呀。因为毕竟没有丢失数据吗。这就是一个TCP从建立传输然后分手的全过程。这其中虽然发生了一点小意外但是TCP凭借着出色的确认号和序列号机制保住了稳定传输这个称号。
希望你不要觉得我讲的很啰嗦。因为我是希望你能彻底的理解这个过程,还有文字的表达毕竟不如语言表达。总之还是希望读者可以彻底的理解和掌握这部分的知识。当然如果你去阿里面试的时候,千万不要把我这一篇原原本本的讲给面试官呀,不然面试官会听睡着,然后默默的和你开启四次分手了。好。希望你可以彻底明白。