点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐]
来自:liweisnake | 责编:乐乐
链接:blog.csdn.net/liweisnake/article/details/51924474
TCP协议目前是事实上的网络基础。许多更高层的应用协议HTTP,FTP都基于TCP。
TCP协议的学习可以说枯燥无比,尤其是学生阶段,根本不知道用在什么地方,根本不知道重要性是什么。事实上是,基于目前的网络发展和分布式发展,TCP简直就是基础中的基础。许多网络的问题,配置,入侵,防御乃至架构,都涉及到TCP的具体应用及机制。
以下是我总结的TCP学习过程,
1. 了解学习TCP协议的重要性和必要性,了解TCP协议为什么被发展出来
推荐这个问题下的各个回答:TCP/IP 协议到底在讲什么?
https://www.zhihu.com/question/51074319
2. 学习TCP协议的三次握手以及四次挥手,重点了解为什么要三次握手,为什么要四次挥手,在整个过程中状态是如何变迁的。(经典的状态图以及握手挥手图)
a.为什么要三次握手?不是一次,两次或者四次。我们来论证一下,如果只有一次会发生什么情况,a向b发起连接请求,假设b没收到,则b其实完全不知道a发起了请求,而a也完全不知道b收没收到,所以一次握手是不可靠的;
如果两次握手呢,a向b发起连接请求,b收到a的请求给a回复一个请求,假设此时a收到了b的回复,a知道了b已经ready了,可b完全不知道a是否ready,有可能a并没有收到b的请求,也有可能收到了,但这些b都完全不知道,所以只是单向的建立了连接;如果是四次握手呢,其实第2次让a知道b ready了,第三次让b知道a也ready了,第四次完全就是多余了,会浪费网络资源。
b.为什么要四次挥手?不是3次?实际上两边连接完全可以分开看,用2次挥手断开其中一边连接,用另外2次挥手断开另一边的连接,最终完成整个连接关闭。之所以这样设计,是因为有可能某一边数据还未传输完,连接还未关闭。因为TCP被设计为全双工协议,可以任何一边单向发送数据。
1. 握手及挥手过程
2. TCP的状态转换图
3. 学习TCP协议是如何保持可靠性设计的。
主要目的是用来参考,以便在其他通信场合时用作架构和设计的参考
1).包应答序列号及包重组。
面临的问题:网络传输中,会出现数据的破坏,丢包,重复,分片混乱等问题。
本质上,要想保证传输的可靠性,则需要对传输的内容进行验证。
a. 对于网络数据的破坏(比如宇宙射线影响偷笑导致发射火箭的数据中某一位从0变为1),采取的策略是丢弃重新发送,以确保不会出现致命的错误。TCP在自身协议中单独划了一块checksum用于这种校验,校验算法本质上是将整块数据通过某个函数映射到16位的校验位上(比如用字符相加的和来校验)
b. 对于数据传输正确,但是分片乱序,重复等问题,或是丢包,采取的策略并非丢弃而是自行进行包重组。
考虑两种情况:第一种情况是某个包缺少了,导致整个数据中间缺了一段1000字节,那么如何通知到对方自己少了哪一段数据;另一种情况是由于网络或者重发机制的原因导致某一个包收到多次,如何把多余的包都排除掉,仅保留已有数据。
TCP在设计时候充分考虑这点,其中SYN和ACK就是用来确保这个过程的,SYN发送的是字节顺序,ACK则应答收到的字节序加1。这样,无论是发送方还是接收方,都可以准确的维护一张发送接收字节的列表。从而可以知道对方还需要哪些字节,或自己已经接收了哪些字节。
2).重发机制
a. 超时重发
为了保证数据一定被接收到,就必须妥善处理超时,对于超时没得到响应,则最好的办法是重新发送。
首先将数据拷贝到发送缓冲区,每个包在发送时都会启动一个定时器,如果定时器超时前收到了对方应答,则发送成功,清除缓冲区,否则重传数据包,直到达到最大次数。
TCP在每次发包时都会计算往返时间极其偏差,通过这个记录可以大致判断双方的网络情况从而确定超时时间。通常刚开始超时时间较长(如6s),而后可能到0.5s这样较小的时间。
b. 高速重发
比起超时才重新发送,TCP还设计了更为巧妙的方式来做重发。称为快速重发。即目标主机在确认时总是确认排在最先的缺失包,当发送方发现连续收到3个同样的ack时,则表明该包已经丢了,需要快速重新发送,这样能否避免要等到超时才能重发。
更多可以参考这里
https://wizardforcel.gitbooks.io/network-basic/content/8.html
3).流量控制(滑动窗口)
a. 滑动窗口协议
滑动窗口本质上是为了在通信过程中同步收发双方的速率。通过发送端的发送窗口和接收端的接收窗口来保证发送的可靠性,同时协调发送的速度。
对于发送端来说,整个窗口分为下面四段,一是已经发送也收到确认回复的;二是已经发送但尚未收到回复的;三是还没有发送但即将发送的(接收方有空间,只是发送方尚未发送而已);四是没发送,但是接收方已经没空间的
同理,对于接收方来说,整个窗口分为三段,一是已经接收并且已经回复ACK的;二是已经接收的;三是为接收也没准备接收的
而所谓的滑动,则是将窗口从上一次收到的连续ACK的位置整个划到下一次收到连续ACK的位置而已。注意连续二字,不连续则不能算作已经接收完毕。
b. 滑动窗口的收缩与扩张
滑动窗口最牛逼的地方在于动态的调整收发双方的窗口大小,以便使得收发双方通信同步而不仅仅是对于发送接收字节的管理。
在TCP协议中,有16个字节专门用来放window大小,是接收端主机向发送方主机通知自己可以接纳的数据大小,而发送方会根据该窗口数据发送不超过这个限度的数据。接收方可以根据自己的处理能力不断的增大或者缩小这个值,而发送方主机则只要保持与之同步即可。
当收缩到最小(即0窗口)时,按照约定发送方不能再给接收方发送数据了,那岂不是陷入死局,大家从此断开?实际上发送方会一段时间后重试,如果还不行拉长一段时间后再重试,直到达到最大重试次数。
4).拥塞控制
拥塞控制的起因是,作为TCP本身虽然已经有了各种校验和检测方法保证通信双方能否互相通信并且能够同步双方的情况了。但是它还忽略了一个关键因素—网络状况。网络是通路,如果这个通路太拥挤,应该适当减少发送,而如果这个通路比较宽松,则可以适当增加发送。
TCP的拥塞控制包括:慢启动,拥塞避免,拥塞发生,快速恢复。
慢启动每次将拥塞窗口的大小设置为1个数据段,之后每次收到确认应答则拥塞窗口加1
由于这很容易造成指数级的增长放大,于是又引入一个慢启动阈值的概念,即当tcp通信开始时,网络吞吐会急剧上升,当到达一个阈值之后,则开始下降然后缓慢上升。
4.TCP中的各种异常攻击情况
1).SYN攻击。主要是建联时攻击。攻击方发起SYN请求,被攻击方收到请求后回应ACK,此时攻击方本应当回应此ACK使得被攻击方变为establish状态,然而攻击方此时不做回应,使得被攻击方维护的未连接队列中该记录存活时间因为超时重试而增加,而短期大量该类型攻击淹没可使得被攻击方未连接队列不断增长,让系统响应变慢,网络拥堵甚至系统崩溃。
2).RST攻击。RST复位主要是通信任何一方认为异常的连接则可以清除该连接的缓冲区,并向对方发送RST标志强制关闭连接。RST攻击主要是用来断一个已有连接的,比如A与B连接中,此时C冒出来伪装成A向B发送一个带RST位的请求,则B将清除所有与A的“记忆”,下次A再来时,B将不认识A;当然了,如果C冒充A向B发送一个SYN请求,则B会主动发起RST复位。这类攻击主要用来瘫痪重要连接,从而趁虚而入。
再叙TIME_WAIT https://huoding.com/2013/12/31/316
TCP 的那些事儿(上) http://coolshell.cn/articles/11564.html
TCP 的那些事儿(下) http://coolshell.cn/articles/11609.html
网络基本功 https://wizardforcel.gitbooks.io/network-basic
觉得本文对你有帮助?请分享给更多人 关注「全栈开发者社区」加星标,提升全栈技能 本公众号会不定期给大家发福利,包括送书、学习资源等,敬请期待吧! 如果感觉推送内容不错,不妨右下角点个在看转发朋友圈或收藏,感谢支持。 好文章,留言、点赞、在看和分享一条龙吧❤️