TCP/IP(3)

实战面试题:

4月份腾讯在南京的面试(跪了),关于TCP/IP的部分:
TCP四次握手,”在发fin后,如果没有收到ack会怎么样?“
但是答的是会重发FIN。问“等多久重发呢?”,答好象是指数退避时间。“指数退避不是链路层的嘛?”,然后就下一个问题了。
现在想了想,应该是超时重传啊,也不清楚当时面试官想要的答案是什么。

接下来就是关于“客户端发送最后一个ACK后,端口可以是否可以立即重用?”,答:处于TIME_WAIT状态,不能立即重用,要等待2MSL时间。“那有什么方法可以加快这个过程吗”,可以设置ADDRESS_REUSE选项,“这个不能解决根本问题啊”,想了一下,好像可以同时设置一个标记,记录上次通信的对端的地址和端口,禁止本机端口和刚刚通信过的地址:端口通信,其他的则可以。这样对过来的数据包进行过滤,可以防止上次通信迟到的数据的干扰。面试官嗯了一下,也没点评,就进入下一个问题了,感觉答的不是很好。
在网上查了一下相关的讨论,发现这应该是TIME_WAIT的快速回收和快速重用的问题:
TIME_WAIT回收
这篇文章作者做了比较详尽的说明,后面的文(字大量摘自该文章,如有侵权,请通知我立即删除)。

   说linux实现了TIME_WAIT的快速回收,使得只需要在TIME\_WAIT状态等待Retrans时间即可释放,就是一个重传时间,想了一下应该是说不靠虑包的网络中的时延,仅仅考虑本端发送的ACK没有被对端收到,对端的第一次重传包到达。
   但是这种快速回收是怎么规避原先TCP协议中提到的可能有迟到的数据包的问题的呢?通过在IP层保留peer信息来实现的,保留的peer信息包括:对端IP地址、peer最后一次被TCP触摸到的时间戳等等。

新的连接请求只有同时触犯了下列三点,才会被拒绝:
1. 来自同一台机器的TCP连接携带时间戳;
2. 之前同一台peer机器(仅仅识别IP地址,因为连接被快速释放了,没了端口信息)的某个TCP数据在MSL秒之内到过本机;
3. 新连接的时间戳小于peer机器上次TCP到来时的时间戳,且差值大于重放窗口戳。

但是这种方式在客户端机器采用NAT地址时会发生混乱,不能正常工作,这是因为NAT设备可能将多个设备的源IP地址都改成了一个IP地址,但是却不修改时间戳。

TIME_WAIT重用

如果能保证以下任意一点,一个TW状态的四元组(即一个socket连接)可以重新被新到来的SYN连接使用:
1.初始序列号比TW老连接的末序列号大
2.如果使能了时间戳,那么新到来的连接的时间戳比老连接的时间戳大。

可以看到,TIME_WAIT快速回收将整机的IP地址列入了考察对象,因为它依据时间戳和保存的peer地址,丢失了端口信息。
而TIME_WAIT的快速重用解决了整机IP地址的问题(考察四元组),但是面临资源消耗的问题(?)。

快速回收和快速重用分别对应linux中net.ipv4.tcp_tw_recycle和net.ipv4.tcp_tw_reuse参数,
reuse参数对客户端作用明显,tw_recycle 对客户端和服务器同时起作用。
这里对reuse和recycle如何应对可能的旧的数据包的问题描述的比较清楚:
前者使能新的outgoing connection重用处于TIME_WAIT状态的端口,只要新的timeStamp比旧的大,只需要等待一秒钟。相比常规的TIME_WAIT状态,怎么达到安全呢?对于旧的连接的迟到数据包,因为TIMEStamp过时了直接丢弃;如果是最后一个ACK丢失的情况,则对端将忽略新连接的SYN,而是直接重发FIN,然后本端发送RST。再重新发送连接。这里有一个问题,如果新连接对端不是之前的对端IP+端口,那么:对于如果新连接已经开始传输数据,突然收到前一个连接对端发过来的FIN,会怎么处理?,还弄的不是很清楚,希望哪位给出解答。
后者对incoming 和 outgoing connection都有影响,通常用在服务器端,且服务器端主动关闭的情况:通过在一定时间内,记住之前对端的地址和Timestamp,然后对新进来的数据包进行比对,如果更早则丢弃;而对于ACK丢失的情况,如果收到旧的连接重发的FIN,也是直接回复RST。

另外:

On the server side, do not enable net.ipv4.tcp_tw_recycle unless you are pretty sure you will never have NAT devices in the mix. Enabling net.ipv4.tcp_tw_reuse is useless for incoming connections.

On the client side, enabling net.ipv4.tcp_tw_reuse is another almost-safe solution. Enabling net.ipv4.tcp_tw_recycle in addition to net.ipv4.tcp_tw_reuse is mostly useless.

Moreover, when designing protocols, don’t let clients close first. Clients won’t have to deal with the TIME-WAIT state pushing the responsability to servers which are better suited to handle this.

这里 作者说tcp_tw_reuse 和SO_REUSEADDR 是两个完全不同的东西,

你可能感兴趣的:(面试,tcp,腾讯)