TCP要保证可靠性, 同时⼜尽可能的提⾼性能:
可靠性
连接管理:
三次握手:
客户端先发起一个建立连接的请求(SYN同步报文段)服务器收到SYN后会立刻返回一个确认报文端ACK,同时回复的这个ACK也是一个SYN。(这两个操作和在一起的原因是因为都是由内核发出的)
涉及到的重要状态:
- LISTEN状态。服务器端的状态。表示随时都可以接受连接
- ESTABLISHED状态: 表示连接已经建立完成
四次挥手:
两边都有可能提出断开连接,以客户端为例,客户端先发出一个断开请求(FIN),服务端接收到以后回复ACK,FIN(ACK是由内核发出的,FIN是程序中调用Socket对象的close方法时才会发送FIN,所以它的速度够快是有可能一起发送的)
涉及到的重要状态:
- CLOSE_WAIT:等待程序最终调用close来完成最终的断开连接过程
如果一个服务器上出现大量的CLOSE_WAIT可能是代码中有bug,没有调用或者没有执行到close。 - 主动关闭方TIME_WAIT的作用:
如果没有TIME_WAIT的后果:在主动方发送的最后一次ACK丢失情况下,主动方用相同的地址信息立即重启。他有可能收到被动关闭方发送的FIN,并且当他给被关闭方发送给FIN的时候,对方等待的时ACK。
所以需要等待2个MSL时间(ACK与FIN),MSL是指的报文的最大生命周期一般是30s。这样可以让网络中延迟的报文都消失在网络中不会对后续连接造成影响。
大量TIME_WAIT产生的原因是:主动关闭方关闭了大量的对端连接,可以通过调整MSL时间,设置套接字选项来解决。
确认应答
对每一条数据向发送方进行确认。每⼀个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下⼀次你从哪⾥开始发。
超时重传
发送后等待一段时间约200ms,如是没有收到则认为数据丢失开始重传。
传输效率:
滑动窗口
收到ACK后再发送下⼀个数据段. 这样做有⼀个⽐较⼤的缺点, 就是性能较差. 尤其是数据往返的时间较长的时候。这样⼀发⼀收的⽅式性能较低, 那么我们⼀次发送多条数据, 就可以大大的提高性能(其实是将多个段的等待时间重叠在⼀起了)
- 窗口大小:指的是不等待ACK可以继续发送数据的最⼤值
- 滑动:每次收到一个ACK之后,就依次发送下一条数据,等待ACK的数据区间就往后移动
- 窗口越大,传输效率越高,但是前提是必须保证接收端可以及时处理到,网络环境可以承载。
- 滑动窗口过程中丢包:
- 如果ACK丢了,并不影响。确认数据表示的是当前序号之前的数据都已经收到了。所以后一个ACK包含了前一个ACK的含义。
- 如果数据丢了,接收端就会反复尝试索要该数据,重复若干次以后,发送端就会认为丢包。并且重传对应的数据。而对于已经发送成功的数据则没必要重新传输一遍。
流量控制
限制滑动窗口大小的一种限制,根据接收端的处理能力进行限制。
接收缓冲区:用来存储传过来的数据。用接收缓冲区的剩余空间来衡量接收端的处理能力。剩的越大处理能力越强。
拥塞控制
根据网络的拥堵情况来限制发送端的发送速率。
试探式的方式
刚开始的时候使用比较小的滑动窗口,如果没有丢包,则增大滑动窗口,如果发生丢包,则减小滑动窗口。先指数增大,再线性增大,当发生丢包后,又将窗口缩得特别小。根据丢包时拥塞窗口的大小来确定线性与指数增长的区间。
滑动窗口是拥塞控制与流量控制所限制的窗口取小。
延时应答
提高传输效率的方式
尽可能提高窗口大小
延时应答导致延时时间中,接收端的程序已经处理了一部分的数据,此时ACK的窗口大小就更大了。
捎带应答
延时应答的基础上,把应用程序发送的业务数据与系统发送的ACK数据合二为一,再提高传输效率。