计算机网络笔记-运输层2


运输层还有很多有趣的事情。

本文的内容:

  1. 四次挥手中的2MSL
  2. 四次挥手中的FIN-WAIT2和CLOSE_WAIT状态详述
  3. 流量控制与拥塞避免
  4. 滑动窗口的三种变化

1.四次挥手中的2MSL

接着<<计算机网络笔记1-运输层>>的介绍,其实处于2MSL中,socket(四元组)是不能再被用的了。所以在2MSL内所有迟来的数据都被丢弃掉,因为在这段时间里,残留的在网络中的数据报会逐渐地消失。

TCP规范也规定,在2MSL内,四元组是不能够被重用的,试想,如果重用了。那么残留的数据报很可能会对新连接造成影响,因为四元组是一样的,那就只是靠序号去做判断了。然后在RFC 1185中被指出,靠序号这种做法仍可能存在缺陷。所以,比较好的做法的,在2MSL内不重用四元组,下一个新的连接客户端应选择别的端口号,这样就会有新的四元组。

那重用四元组的手段是什么呢? 很多实现中其实都有提供SO_REUSEADDR这个选项,它能够使得在2MSL内重用端口。具体可以参考这个用python写的服务端代码。你可以通过注释SO_REUSEADDR所在的语句来观察结果。

实际上,2MSL是发生在被关闭的那一端,意思是服务端在接受到客户端的FIN时也会发起2MSL。


2.四次挥手中的FIN-WAIT2和CLOSE_WAIT状态详述

先看图:

TCP four-way handshake

FIN-WAIT2状态是等待服务端发起FINCLOSE_WAIT状态是服务端自身的等待。

先讲CLOSE_WAIT状态,为什么服务端自身在等待呢? 因为这时候是半关闭,服务端仍可能有数据往客户端发送。而图中的通知应用进程的箭头,就是收到来客户端的FIN,然后会为数据的末尾添加一个文件结束符(EOF)以此来通知应用进程。具体这里还可以参考POSIX里的recv/recvfrom/recvmsg(sys/socket.h)这三个函数对返回值的定义。

那么问题来了,万一服务端永远待在CLOSE_WAIT状态怎么办? 在实际的实现中,会采用定时器之类的方法进行强制关闭。


3.流量控制与拥塞避免

流量控制是针对接受方的。 因为在接收方中有接受缓存,发送方即使发送再多也会被丢弃。根据接受方的接受缓存窗口大小,也可以控制双方的发送速率与接受速率。

拥塞避免是针对发送方的。 如果接收方的接受缓存可以很大,是否意味着发送方就可以提高发送的速率呢?不是的,因为在网络中会存在速率较慢的链路,这样在这些区域的路由器就会缓存数据,路由器的缓存是有限的,达到最值就会溢出。假如数个速率不加限制地往接收方发送数据,甚至会在某个路由器或某个区域造成拥塞,把整个网络的吞吐量等性能都拉低。所以发送方是必须做拥塞避免的。


4. 滑动窗口的三种变化

  1. 窗口左边沿向右边沿靠近为窗口合拢。这种变化是因为收到ACK。
  2. 窗口右边沿向右移动从而允许发送更多的数据,称为窗口张开。这种变化是因为接受进程读取已经确认的数据,因而释放了接收方的接受缓存。
  3. 窗口右边沿向左移动,称为窗口收缩。这种方式不被建议实现。

在发送方,发送缓存的窗口值必须小于或等于接收方在TCP首部添的16位窗口值。什么时候会小于?滑动窗口第一种变化就会小于。

本文会随着review而保持更新