为什么我们需要三向握手?为什么不只是2路?


124

TCP 3向握手的工作方式如下:

Client ------SYN-----> Server
Client <---ACK/SYN---- Server
Client ------ACK-----> Server

为什么不只是这个呢?

Client ------SYN-----> Server
Client <-----ACK------ Server

24
为什么我们甚至需要握手?为什么不能与第一个数据包一起发送消息?
Mehrdad 2015年

4
如果要跳过握手,则可以改用UDP。
OzNetNerd

5
@Mehrdad,如果您有自己的问题,请使用页面顶部的“ 提问”链接发布您自己的问题。
YLearn

40
@YLearn:对不起,这并不是我自己的问题,而是要激励读者给出比问题中所讲内容更深入的答案。
Mehrdad 2015年

3
不要忘记TCP快速开放(RFC 7413)
Alnitak

Answers:


158

将握手分解为实际操作。

在TCP中,双方通过使用序列号来跟踪发送的内容。实际上,它最终是发送的所有内容的运行字节数。接收方可以使用对方讲话者的序列号来确认接收到的内容。

但是序列号不是从0开始。它从ISN(初始序列号)开始,这是一个随机选择的值。并且由于TCP是双向通信,双方都可以“讲话”,因此双方都必须随机生成一个ISN作为其起始序列号。反过来,这意味着双方都需要将其初始ISN通知另一方。

因此,您以以下事件序列结束,开始了Alice和Bob之间的TCP对话:

Alice ---> Bob    SYNchronize with my Initial Sequence Number of X
Alice <--- Bob    I received your syn, I ACKnowledge that I am ready for [X+1]
Alice <--- Bob    SYNchronize with my Initial Sequence Number of Y
Alice ---> Bob    I received your syn, I ACKnowledge that I am ready for [Y+1]

注意,发生了四个事件:

  1. 爱丽丝选择一个ISN并将其与鲍勃同步
  2. Bob 确认了ISN。
  3. 鲍勃选择一个ISN并将其与爱丽丝同步
  4. 爱丽丝确认 ISN。

实际上,中间的两个事件(#2和#3)发生在同一数据包中。使数据包成为一个SYNACK仅仅是使每个TCP标头中的二进制标志处于打开或关闭状态的原因是什么,所以没有什么可以阻止在同一数据包上同时启用这两个标志。因此,三向握手最终为:

Bob <--- Alice         SYN
Bob ---> Alice     SYN ACK 
Bob <--- Alice     ACK     

请注意两个方向上“ SYN”和“ ACK”的两个实例,每个实例之一。


因此,回到您的问题上,为什么不仅仅使用双向握手?简短的答案是因为双向握手只会允许一方建立一个ISN,而另一方承认它。这意味着只有一方可以发送数据。

但是TCP是双向通信协议,这意味着任何一端都应该能够可靠地发送数据。双方都需要建立一个ISN,并且双方都需要确认对方的ISN。

因此,实际上,您所拥有的只是双向握手的描述,但是在每个方向上。因此,发生了四个事件。同样,中间两个标志出现在同一数据包中。这样,三个数据包将包含在完整的TCP连接启动过程中。


6
为什么我们根本需要ISN?人类不需要它,为什么要使用计算机?有证据吗?还是因为方便,我们就拿它们吗?
Mehrdad 2015年

19
@Mehrdad:您需要序列号才能进行重新传输,以使其正常工作(或完全不工作)。由于序列预测攻击,ISN不能只是零。
凯文

4
@Mehrdad聊天室不一定必须是“实时”的,我们可以互相留言。我之所以将其转至其他地方,是因为您现在在问一个不同的问题。OP询问“为什么它是3次握手而不是2次握手”,但是现在您质疑“为什么我们根本需要序列号”,这是不同的。我认为我们应该在聊天中讨论另一个问题,而不是使该线程出轨。 或者,您可以发布一个新问题,我敢肯定,它将获得一些不错的答案。
艾迪(Eddie)2015年

4
简明扼要的答案。读“ ACK SYN”从根本上来说是错误的,但您甚至解释了+1。
Lilienthal 2015年

3
根据RFC 793,传输控制协议:“ 三向握手的主要原因是为了防止旧的重复连接启动引起混乱。
罗恩·莫平

23

因为双方都需要的三次握手是必要的顺式 chronize其传输过程中所使用的部分序列号。为此,它们中的每发送(依次)设置为随机值的序列号的SYN段Ñ,其然后被ACK由另一方经由与设置为序列号的ACK段那位博n + 1个


为什么需要确认?
圣保罗Ebermann

4
@PaŭloEbermann:因为否则服务器不知道客户端是否曾经收到过SYN,因此客户端收到该消息很重要。
Mooing Duck

2
@PaŭloEbermann为了证明这一点,ACK步骤是用[X + 1]进行确认。-引用Eddie的评论对他的回答。
smwikipedia

14

为了使连接正常工作,每一端都需要验证是否可以将数据包发送到另一端。确保您收到另一端的数据包的唯一方法是从他们那里获得一个数据包,根据定义,除非您发送的数据包通过,否则这些数据包不会被发送。TCP 本质上为此使用两种消息:SYN(请求证明此数据包已通过)和ACK(仅在SYN通过后才发送,以证明SYN已通过)。实际上有第三种信息,但是我们稍后会谈到。

在连接开始之前,任何一方都不了解对方。客户端将SYN数据包发送到服务器,以请求证明其消息可以通过。那没有告诉任何人任何信息,但这是握手的第一步。

如果SYN通过,则服务器知道客户端可以向其发送数据包,因为它刚发生。但这并不能证明服务器可以发回数据包:客户端可以出于多种原因发送SYN。因此,服务器需要将两个消息发送回客户端:一个ACK(证明SYN通过了)和一个SYN(请求自己的ACK)。TCP将这两个消息合并为一个-SYN-ACK消息(如果愿意),以减少网络流量。这是握手的第二步。

由于SYN-ACK是ACK,因此客户端现在确定可以将数据包发送到服务器。并且因为SYN-ACK是SYN,所以它也知道服务器希望证明此消息已通过。因此它发送回一个ACK:这次只是一个普通的ACK,因为它不再需要证明其数据包可以通过的证据。这是握手的最后一步:客户端现在知道数据包可以双向传输,并且服务器即将解决此问题(因为它知道ACK将通过)。

一旦该ACK通过,现在服务器便知道可以向客户端发送数据包了。它还知道客户端知道这一点,因此它可以立即开始发送数据。握手完成。我们有一个很好的渠道。

好吧,严格来说,我们不能确定我们拥有良好的渠道。仅因为此顺序的数据包通过并不能严格保证其他人会通过。我们无法证明,如果不发送无限数量的SYN和ACK,那么将一事无成,因此这不是一个实际的选择。但是实际上,三个步骤对于大多数目的来说已经足够了


这是不正确的:“一个ACK(仅在响应SYN时发送,因此证明SYN通过了)。” 只有从两端发送的第一个数据包都设置了SYN标志,而除三向握手的第一个数据包以外的所有数据包都设置了ACK标志。第一个数据包无法进行ACK,因为第二方尚未进行SYNed,但是第一个数据包之后的每个数据包都必须ACK,以确认是否已经从另一端接收到了任何数据,无论是否发送回任何数据。
蒙迪·哈德

谢谢。重措词:SYN通过后才发送ACK,而不是仅响应SYN而发送。
The Spooniest

这是最好的答案,可以从逻辑上解释为什么我们甚至需要第三条消息。谢谢,傻瓜。
Parth Patel

7

实际上,三向握手并不是建立TCP连接的唯一方法。还允许同时进行SYN交换:http ://www.tcpipguide.com/free/t_TCPConnection EstablishmentmentProcessTheThreeWayHandsh-4.htm

这可以看作是两次双向握手。


1
好的一点是,但是这非常罕见,因为两个设备都必须使用相同的源/目标端口,并且两个设备都需要在另一个接收SYN之前发送SYN。即使发生这种情况,它也要发送四个数据包,这比传统的三向握手所需的三个数据包还多。最终只有在总体时间上稍微加快设置速度的可能性,而总体效率却降低了(需要传输的数据包增加33%)。
YLearn

4

TCP连接是双向的。这意味着它实际上是一对单向连接。发起方发送SYN,响应方发送ACK:一个单纯形连接开始。“然后”响应者发送SYN,发起者发送ACK:另一个单纯形连接开始。两个单工连接形成一个双工TCP会话,同意吗?因此,从逻辑上讲,涉及四个步骤;但是由于SYN和ACK标志是TCP报头的不同“字段”,因此可以同时设置它们-第二步和第三步(四个步骤)被组合在一起,因此从技术上讲,存在三个数据包交换。如您所建议的,每个单工(半)连接都使用2路交换。


2

如果服务器和客户端要创建连接,则需要确认四件事:

  1. 服务器需要确认他可以从客户端接收数据包
  2. 客户端需要确认他可以从服务器接收数据包

  3. 客户端需要确认一件事:服务器可以从客户端接收数据包

  4. 服务器需要确认一件事:客户端可以从服务器接收数据包

之后Client ------SYN-----> Server,确认规则1。

之后Client <---ACK/SYN---- Server,确认规则2和3。

因此,需要第三个数据包来确认规则4。


1

完全没有必要。显然,一条短消息只需要向服务器发送一个包含开始+消息的数据包,并向后发送一个确认它的数据包。

前面的答案仅描述了系统,而没有首先讨论对随机序列号等的需求。最初的问题是关于TCP本身的设计的-显然,如果您使用TCP协议,则需要三个消息,因为这是该协议。但是,为什么TCP首先要采用这种方式设计?

我相信最初的想法是客户端和服务器之间没有区别。双方都以双向方式知道对方的端口,并且任何一方都可以开始对话。而这需要Syns等

但这当然不是今天的用法。服务器在一个众所周知的端口上侦听并“接受”,客户端端口号是临时的。我什至认为在正常操作系统中,等待“接受”的服务器不可能在同一客户端端口号上向另一个发送请求。

(请注意,这是关于双向启动连接的,今天从未做过。这与在建立连接后通过连接发送双向消息完全不同。)

要解决TCP效率低下的问题,我们使用HTTP 1.1之类的协议,该协议可以将同一连接重用于多个请求,从而避免了TCP握手,而这种握手一开始就没有必要。

但是Http 1.1相对较新。由于PKI算法的成本,SSL / TLS从一开始就需要一种重用会话的方法。因此,该协议包括自己的会话重用机制,该机制在Http 1.1之上运行,而HTTP 1.1在TCP之上运行。

软件就是这样。捏在一起的软糖会产生可接受的结果。


OSI第4层以上的所有内容(例如HTTP,FTP等)在这里都明确不在主题之列。在第1到第4层中,没有客户端/服务器之类的东西。TCP是对等点之间的连接。是的,上层协议创建了客户端/服务器关系,但是在这里是不合主题的。
罗恩·莫平

1
顺便说一句,HTTP使用TCP,因此TCP握手仍然是必需的。阅读RFC 793传输控制协议以了解其原因。像HTTP这样的协议要求应用程序执行TCP通常对应用程序执行的多路复用。
罗恩·莫平

@RonMaupin最初的问题是为什么?答案是要支持一个用例,该用例实际上是高层不使用的。因此,似乎很相关。
可调式

@RonMaupin是的,HTTP使用TCP。我已经澄清了,谢谢。但这在任何意义上都没有必要进行TCP握手。
调谐的'16

1
在这里,应用程序和应用程序层协议明确不在主题之列。@Eddie回答了这个问题,如果您阅读并理解了TCP RFC,您将了解为什么需要握手。在没有任何支持的情况下,我认为这并没有增加任何要求,即握手是不必要的,但显然没有必要。
罗恩·莫平

1

在阅读了Eddie的答案(被接受为正确的答案)之后,仍然存在一个问题,为什么第一个主机不能同时为两个ISN分配随机数,而第二个主机只能接受它。使用三向握手的真正原因是为了避免半连接。2次握手的半连接情况:
1)客户端--- SYN->服务器
2)客户端改变了主意,不想再连接
3)客户端<-X-ACK--服务器// ACK丢失
服务器未看到重新发送的SYN,因此他认为客户端得到了ACK并建立了连接。因此,服务器具有永远不会关闭的连接


实际上,如果主机(客户端和服务器是TCP对其一无所知的应用程序概念)在不存在的连接上收到ACK或任何流量(您的方案中的步骤3),它将发送RST,而不忽略接收到的段。
罗恩·莫平

@RonMaupin然后让我们假设ACK数据包丢失的情况。
Sanzhar Yeleuov '18

如果ACK丢失,则在步骤1中启动的连接将超时。RFC 793全面解释了所有类型的场景,包括图表。
罗恩·莫平

@RonMaupin我的意思是,如果我发帖中的场景保持不变,则只有发生了变化的那个ACK丢失了。
Sanzhar Yeleuov '18

全部在RFC中。在打开连接之前,收到的所有流量都将导致RST。三向握手协商连接参数,因此“服务器”无法将任何内容发送回“客户端”,但它是SYN / ACK,直到从“客户端”接收到ACK。如果丢失了返回到“客户端”的“服务器” SYN / ACK,则“服务器”将重试。RFC解释了所有这一切。
罗恩·莫平
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.