只知道它有三次握手和四次挥手是不足以应付严格的面试官的...
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
我们熟悉的HTTP就是基于TCP来的。
TCP连接在面试中也是一个很高频的话题,一般面试官的起手式为:请讲讲TCP的三次握手/四次挥手...
本文大纲如下,看不完可以收藏慢慢看(看完怕忘也是)
入门级回答,简单描述下客户端和服务端之间每次在做什么。
发起连接请求的是客户端,接收连接请求的是服务端。
对于图中的几个关键词,是TCP报文中的控制位中的标志(为1表示有对应标志)
完成这三个步骤后客户端和服务端建立起深厚的友谊,开始你来我往,传递数据。当双发无话可说时,友谊的小船说翻就翻。
断开连接可以由任意一方先提出,一般是客户端提出的。
上面的描述比较简单,我们可以更加深入探索客户端和服务端之间的种种行为。
服务端处于监听状态(LISTEN),随时准备接受连接。
完成这四个步骤后(只是多了一个状态变化的描述,还是三次握手哈)客户端和服务端再次建立起深厚的友谊,开始你来我往,传递数据。
当然天下无不散之筵席,挥手再见的时刻即将到来。
还是客户端先提出分手。
对于上面描述的过程,如果你之前不太了解,那么针对某些点肯定会有些许疑问。
下面总结一些可以延伸的问题。
为何是三,不是二,也不是四?借助经典的打电话的场景来帮助理解。
在三次握手之后,A和B都能确定这么一件事:我说的话,你能听到;你说的话,我也能听到。如此这般,就可以开始愉快地交流了。
为什么不能像建立连接那样三次?毕竟三次就能保证互相知晓了。
回顾上面的图,可以看到服务端得知客户端想要断开连接后,先给客户端发了一个ACK包,然后又发了一个FIN包,问题的关键在于这两步能否合并,如果可以那么就可以精简为三次挥手。
答案当然是不可以。因为服务端得知客户端想断开连接时,它这边可能还有些事没处理完,比如还有些消息没发完(我还有话说系列)。等它处理好后,再给客户端发送一个FIN包,表示它也可以结束了,这是客户端再发个ACK包到服务端,表示他知道了。
这个问题笔者面试时被问到过,当时自信且流畅地说完TCP的连接过程,甚至在内心默默给自己点了个赞。。。后面不说也罢。
TCP的报文构造还是有点复杂的,这里不讨论了,网上找了个图(来源见水印)。
可以看到上面曾有过出镜的FIN、ACK、SYN等东东,这些都存在报文对应位置。
发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到接受方的接收能力,发送窗口可能小于拥塞窗口。
发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期
timewait是主动关闭的一方会出现的状态,当收到对方发来的FIN包并返回一个ACK后,进入timewait。
time_wait存在的原因有两点
timewait大量出现的场景,一般是服务端,因为一般是大量客户端连接少量服务端。虽然一般是客户端主动断开连接,但某些情况也可能是客户端向服务端发送一个信息,然后服务端主动关闭。这样就可能导致服务端短时间内出现大量timewait状态,而占用了资源致使不能创建更多的socket。
几个解决思路:
close_wait是被动关闭的一方出现的状态,出现原因时,收到要关闭的信号后,自己这边还有些事情没处理完,导致迟迟不能发送FIN包给主动断开的一方。
所以说,一般大量出现都是我们的程序有问题,建议改代码。
通过netstat命令可以查看各种状态的连接数量,举个栗子:
➜ ~ netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c
1 CLOSED
8 CLOSE_WAIT
1 CLOSING
42 ESTABLISHED
1 FIN_WAIT_1
2 FIN_WAIT_2
2 LAST_ACK
20 LISTEN
3 SYN_SENT
1 com.apple.network.tcp_ccdebug