这个问题网络上的回答超级多,众说纷纭。以 RFC 793 来回答这个问题可能更加准确。
Reliability:
The TCP must recover from data that is damaged, lost, duplicated, or delivered out of order by the internet communication system. This is achieved by assigning a sequence number to each octet transmitted, and requiring a positive acknowledgment (ACK) from the receiving TCP. If the ACK is not received within a timeout interval, the data is retransmitted. At the receiver, the sequence numbers are used to correctly order segments that may be received out of order and to eliminate duplicates.
首先,文档表明了 TCP 是通过 序列号 seq + 应答 ACK 来实现可靠性的。
既然是通过序列号来实现可靠性的,那是不是首先得有个 初始序列号 呢,对吧。
此外,TCP 是全双工通信,那是不是通信的双方都要有这样一个初始序列号,没错吧。
The protocol places no restriction on a particular connection being used over and over again. A connection is defined by a pair of sockets. New instances of a connection will be referred to as incarnations of the connection. The problem that arises from this is -- "how does the TCP identify duplicate segments from previous incarnations of the connection?" This problem becomes apparent if the connection is being opened and closed in quick succession, or if the connection breaks with loss of memory and is then reestablished.
然后,文档还说,TCP 没有限制 连接的 重复使用(通信双方的 IP 端口一样)。这会引发一个问题:在一个连接断开并快速重连的时候,新的连接可能成为旧连接的一个化身,此时,TCP 怎么识别数据是否是来自旧连接?
怎么识别呢?
现在不是正好有个初始序列号,思考一下它可不可以用来识别不同的连接呢?
答案是可行的,只要 保证每个连接的初始序列号是不一样的,就可以利用这个 “唯一” 的初始序列号来区分不同的连接了,对吧。
因此,初始序列号 这个东西就是重点了,它既是 TCP 可靠通信的一个起点,还可以解决重复连接的问题。
先看下 初始序列号(ISN)的生成规则。
在一个连接建立的时候,初始序列号生成器会生成一个 32 位的 ISN。这个生成器绑定到一个 32 位长的时钟,差不多 4µs 增长一次。因此 ISN 会在大约 4.55 小时循环一次。而一个段在网络中存留的最大时间为 Maximum Segment Lifetime (MSL) ,默认使用2分钟,MSL 比 4.55 小时要短,所以可以认为 ISN 是唯一 的。
ISN 生成规则表明它是唯一的,因此,我们可以利用它来区分不同的连接。
现在剩下的问题就是怎么 同步双方的 ISN 了,原问题也可以转换成:两次握手可以完成 初始序列号的同步吗?
A three way handshake is necessary because sequence numbers are not tied to a global clock in the network, and TCPs may have different mechanisms for picking the ISN's. The receiver of the first SYN has no way of knowing whether the segment was an old delayed one or not, unless it remembers the last sequence number used on the connection (which is not always possible), and so it must ask the sender to verify this SYN.
文档给了我们答案,因为序列号没有绑定到整个网络中的一个全局时钟,此外,TCP 可能有不同的机制来生成初始序列号 ISN。因此,接收方接收到第一个 SYN 时,没有办法区分这个 SYN 是否来自旧连接,除非它有办法记住在这条连接最后收到的那个序列号(然而这不总是可行的),所以它必须向发送者确认这个同步信息。
也就是说只有 生成 ISN 的一方才可以确认这个 ISN 是不是对的。
如果只有两次握手,就只有主动发起方的 ISN 被确认了,而 TCP 是全双工通信,所以我们可以得到结论,两次握手是不可以的。
综上所述,我觉得可以这样回答这个问题:
首先,TCP 是全双工通信,而且 TCP 是通过 序列号来实现可靠传输的,因此一个连接首先要 同步双方起始序列号(ISN),才可以保证通信双方的数据准确性;而 ISN 的生成规则告诉我们只有生成 ISN 的一方才可以确认这个 ISN 是不是正确的,因此,需要三次握手来保证通信双方 ISN 的同步,如果只有两次握手,只能保证 发起方的 ISN 被确认,也就只能保证发起方向服务方的单向通信的数据可靠性。
此外,TCP 还利用 ISN 在三次握手的过程中 解决了 历史连接初始化带来的数据混乱问题。
网络上对于这个问题争论不休,一些说为了防止资源浪费,一些说是为了防止 旧的重复连接初始化造成混乱(The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion ),我觉得大部分只看到了字面意思,没有把整个逻辑理顺。
当然,本文也只是个人对这个问题的一点见解,有不同意见的可以一起讨论。
此外,文档还列举了一个异常处理案例:

图解:
1、客户端发起连接请求,假设这次初始序列号 seq = 90;由于网络原因,该包还没有到达服务端,而客户端此时放弃了这次连接;然后客户端重新向服务端发起了一个 新的连接 请求,假设这次初始化序列号 seq = 100;
2、第一次连接发送的同步请求到达了服务端,而服务端是无法知道这是来自旧连接的同步请求的,因此正常响应该同步请求,应答序列号 ack = 91;
3、客户端收到应答后,发现不是期望的应答序列号 101,因此返回了 RST 的控制信息了;服务端收到该 RST 信息,重新回到 LISTEN状态;
4、此时,第二次连接发送的同步请求到达了服务端,接着就是正常的三次握手。
本文解析了TCP如何通过序列号实现可靠传输,重点讲解了初始序列号(ISN)的作用,指出三次握手的必要性,以确保新连接的唯一性和旧连接的区分。讨论了ISN生成规则、同步过程以及为何需要三次握手而非两次。
499

被折叠的 条评论
为什么被折叠?



