1、前言
TCP是一个巨复杂的协议,因为他要解决很多问题,而这些问题又带出了很多子问题和阴暗面。所以学习TCP本身是个比较痛苦的过程,但对于学习的过程却能让人有很多收获。
2、本文目的
之所以想写这篇文章,目的有三个:
-
1)一个是想锻炼一下自己是否可以用简单的篇幅把这么复杂的TCP协议描清楚的能力。
-
2)另一个是觉得现在的好多程序员基本上不会认认真真地读本书,喜欢快餐文化,所以,希望这篇快餐文章可以让你对TCP这个古典技术有所了解,并能体会到软件设计中的种种难处。并且你可以从中有一些软件设计上的收获。
-
3)最重要的希望这些基础知识可以让你搞清很多以前一些似是而非的东西,并且你能意识到基础的重要。
所以,本文不会面面俱到,只是对TCP协议、算法和原理的科普。
3、系列文章
我本来只想写一个篇幅的文章的,但是TCP真TMD的复杂,比C++复杂多了,这30多年来,各种优化变种争论和修改。所以,写着写着就发现只有砍成两篇:
- 《[通俗易懂]深入理解TCP协议(上)》:主要向你介绍TCP协议的协议头、状态机、数据重传中的东西。(本文)
- 《[通俗易懂]深入理解TCP协议(下)》:重点介绍TCP的流迭、拥塞处理等。
4、基础知识
废话少说,首先,我们需要知道TCP在网络OSI的七层模型中的第四层——Transport层,IP在第三层——Network层,ARP在第二层——Data Link层,在第二层上的数据,我们叫Frame,在第三层上的数据叫Packet,第四层的数据叫Segment。
首先,我们需要知道,我们程序的数据首先会打到TCP的Segment中,然后TCP的Segment会打到IP的Packet中,然后再打到以太网Ethernet的Frame中,传到对端后,各个层解析自己的协议,然后把数据交给更高层的协议处理。
5、TCP协议头的格式
接下来,我们来看一下TCP头的格式:
你需要注意这么几点:
- 1)TCP的包是没有IP地址的,那是IP层上的事,但是有源端口和目标端口。
- 2)一个TCP连接需要四个元组来表示是同一个连接(src_ip, src_port, dst_ip, dst_port)准确说是五元组,还有一个是协议。但因为这里只是说TCP协议,所以,这里我只说四元组。
相关视频推荐
金三银四C++面试-有了TCP为何还要用UDP/FFmpeg/webRTC/rtmp/hls/rtsp/ffplay/srs
注意上图中的四个非常重要的东西:
- 1)Sequence Number:是包的序号,用来解决网络包乱序(reordering)问题。
- 2)Acknowledgement Number:就是ACK——用于确认收到,用来解决不丢包的问题。
- 3)Window:又叫Advertised-Window,也就是著名的滑动窗口(Sliding Window),用于解决流控的。
- 4)TCP Flag :也就是包的类型,主要是用于操控TCP的状态机的。
关于其它的东西,可以参看下面的图示:
6、TCP的状态机
其实,网络上的传输是没有连接的,包括TCP也是一样的。而TCP所谓的“连接”,其实只不过是在通讯的双方维护一个“连接状态”,让它看上去好像有连接一样。所以,TCP的状态变换是非常重要的。
下面是:“TCP协议的状态机”(图片来源) 和 “TCP建链接”、“TCP断链接”、“传数据” 的对照图,我把两个图并排放在一起,这样方便在你对照着看。另外,下面这两个图非常非常的重要,你一定要记牢。(吐个槽:看到这样复杂的状态机,就知道这个协议有多复杂,复杂的东西总是有很多坑爹的事情,所以TCP协议其实也挺坑爹的)
很多人会问,为什么建链接要3次握手,断链接需要4次挥手?
- 1)对于建链接的3