1、UDP和TCP的特点与区别
用户数据报协议UDP(User Datagram Protocol)
是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加UDP首部),支持一对一、一对多、多对一和多对多的交互通信。
传输控制协议TCP(Transmission Control Protocol)
是面向连接的,提供可靠支付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成是字节流,把字节流组织成大小不等的数据块),每一条TCP连接只能是点对点的(一对一)。
2、UDP、TCP首部格式
UDP首部只有8个字节,包括源端口、目的端口、长度和校验和。12字节的伪首部是为了计算检验和临时添加的。
TCP首部比UDP复杂。
序号:用于对字节流进行编号,例如序号为301,表示第一个字节的编号为301,如果携带的数据长度为100字节,那么下一个报文段的序号应该为401.
确认号:期望收到的下一个报文段的序号。例如B正确收到A发送来的一个报文段,序号为501,携带的数据长度为200字节,因此B期望下一个报文段的序号为701,B发送给A的确认报文段中确认号为701.
数据偏移:指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。
控制位:八位从左到右分别是CWR、ECE、URG、ACK、PSH、RST、SYN、FIN。
CWR:CWR标志与后面的ECE标志都用于IP首部的ECN字段,ECE标志为1时,则通知对方已将拥塞窗口缩小。
ECE:若其值为1则会通知对方,从对方到这边的网络有阻塞。在收到数据包的IP首部中ECN为1时将TCP首部中的ECE设为1.
URG:该位设为1,表示包中有需要紧急处理的数据,对于需要紧急处理的数据,与后面的紧急指针有关。
ACK:该位设为1,确认应答的字段有效,TCP规定除了最初建立连接时的SYN包之外该位必须设为1.
PSH:该位设为1,表示需要将收到的数据立刻传给上层应用协议,若设为0,则先将数据进行缓存。
RST:该位设为1,表示TCP连接出现异常必须强制断开连接。
SYN:用于建立连接,该位设为1,表示希望建立连接,并在其序列号的字段进行序列号初值设定。
FIN:该位设为1,表示今后不再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交互FIN位置字段为1的TCP段。
每个主机又对对方的FIN包进行确认应答之后可以断开连接。不过,主机收到FIN设置为1的TCP段之后不必马上回复一个FIN包,而是可以等到缓冲区中的所有数据都因为已成功发送而被自动删除之后再发FIN包。
窗口:窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。
3、什么是TCP的三次握手和四次握手?
TCP是一种面向连接的单播协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务器的内存里保存的一份关于双方的信息,如IP地址、端口号等。
TCP可以看成是一种字节流,它会处理IP层或以下的层的丢包、重复以及错误问题。在连接的建立过程中,双方需要交换一些连接的参数。这些参数可以放在TCP头部。
TCP提供了一种可靠、面向连接、字节流、传输层的服务,采用三次握手建立一个连接;采用四次握手来关闭一个连接。
一个TCP连接有一个4元组构成,分别是两个IP地址和两个端口号。一个TCP连接通常分为三个阶段:启动、数据传输、退出(关闭)。
当TCP接收到另一端的数据时,它会发送一个确认,但这个确认不会立即发送,一般会延迟一会。
ACK是累积的,一个确认字节号N的ACK表示所有直到N的字节(不包括N)已经成功被接收了。这样的好处是如果一个ACK丢失,很可能后续的ACK就足以确认前面的报文段了。
一个完整的TCP连接是双向的和对称的,数据可以在两个方向上平等地流动。给上层应用程序提供一种双工服务。一旦建立了一个连接,这个连接的一个方向上的每个TCP报文段都包含了相反方向上的报文段的一个ACK。
序列号的作用是使得一个TCP接收端可丢弃重复的报文段,记录以杂乱顺序到达的报文段。因为TCP使用IP来传输报文段,而IP不提供重复消除或者保证次序正确的功能。
另一方面,TCP是一个字节流协议,绝不会以杂乱的次序给上层程序发送数据。因此TCP接收端会被迫先保持大序列号的数据不交给应用程序,直到缺失的小序列号的报文段被填满。
4、TCP的三次握手(为什么三次)
假设A为客户端,B为服务器端。
首先B处于一种监听状态,等待客户的连接请求。
① A向B发送连接请求报文,此时SYN = 1,ACK = 0,同时选择一个初始的序号x。
② B收到A的连接请求报文后,如果同意建立建立,则需要向A发送一个连接确认报文,SYN=1,ACK=1,确认号为x+1,同时选择一个初始的序号y。
③ A收到B的连接确认报文后,还要向B发出确认,确认号为y+1,序号为x+1。
B收到A的确认后,建立连接。
为什么三次?
① 第三次握手是为了防止失效的连接到达服务器,让服务器错误打开连接。
② 客户端和服务端通信前要进行连接,“三次握手”的作用就是让对方都能明确自己和对方的收、发能力是正常的。
第一次握手:客户端发送网络包,服务器收到了。这样服务器就能得出结论:客户端的发送能力、接收能力是正常的。
第二次握手:服务器发包,客户端收到了。这样客户端就能得出结论:服务器的接收、发送能力,客户端的接收能力、发送能力是正常的。从客户端的视角来看,我接收到了服务器发来的响应数据包,这就说明,服务器的接收、发送能力正常。而另一方面,我收到了服务端的响应数据包,说明我第一次发送的网络包成功到达服务器端。这样,客户端的发送和接收能力也是正常的。
第三次握手:客户端发包,服务器收到了。这样服务器就可以得出结论:客户端的接收、发送能力,服务器端的发送、接收能力正常。第一、二次握手后,服务器端并不知道客户端的接受能力以及自己的发送能力是否正常。
而在第三次握手时,服务端收到了客户端对第二次握手作的回应。从服务端的角度,我在第二次握手时的响应数据发送出去了,客户端接收到了。所以,我的发送能力是正常的。而客户端的接收能力也是正常的。
经历了上面的三次握手过程,客户端和服务端都确认了自己的接收、发送能力是正常的。之后就可以正常通信了。
每次都是接收到数据包的一方可以得到一些结论,发送的一方其实没有任何头绪。我虽然有发包的动作,但是我怎么知道我有没有发出去,而对方有没有接收到呢?
而从上面的过程可以看到,最少是需要三次握手过程的。两次达不到让双方都得出自己、对方的接收、发送能力都正常的结论。
其实每次收到网络包的一方至少是可以得到:对方的发送、我方的接收是正常的。而每一步都是有关联的,下一次的“响应”是由于第一次的“请求”触发,因此每次握手其实是可以得到额外的结论的。
比如第三次握手时,服务端收到数据包,表明看服务端只能得到客户端的发送能力、服务端的接收能力是正常的,但是结合第二次,说明服务端在第二次发送的响应包,客户端接收到了,并且作出了响应,从而得到额外的结论:客户端的接收、服务端的发送是正常的。
5、TCP的四次挥手(为什么四次?)
客户端发送一个 FIN 段,并包含一个希望接收者看到的自己当前的序列号 K. 同时还包含一个 ACK 表示确认对方最近一次发过来的数据。
服务端将 K 值加 1 作为 ACK 序号值,表明收到了上一个包。这时上层的应用程序会被告知另一端发起了关闭操作,通常这将引起应用程序发起自己的关闭操作。
服务端发起自己的 FIN 段,ACK=K+1, Seq=L。
客户端确认。进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。ACK=L+1。
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
1、TCP连接是双向传输的对等的模式,就是说双方都可以同时向对方发送或接收数据。当有一方要关闭连接时,会发送指令告知对方,我要关闭连接了。
2、这时对方会回一个ACK,此时一个方向的连接关闭。但是另一个方向仍然可以继续传输数据,也就是说,服务端收到客户端的 FIN 标志,知道客户端想要断开这次连接了,但是,我服务端,我还想发数据呢?我等到发送完了所有的数据后,会发送一个 FIN 段来关闭此方向上的连接。接收方发送 ACK确认关闭连接。
注意,接收到FIN报文的一方只能回复一个ACK, 它是无法马上返回对方一个FIN报文段的,因为结束数据传输的“指令”是上层应用层给出的,我只是一个“搬运工”,我无法了解“上层的意志”。
3、客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。
4、因为服务端在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。而关闭连接时,当收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方 ACK 和 FIN 一般都会分开发。
TIME_WAIT
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。
5、TCP可靠传输
TCP使用超时重传来实现可靠传输:如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。
一个报文段从发送到接收到确认所经过的时间称为往返时间RTT,加权平均往返时间RTTs计算如下:
R
T
T
s
=
(
1
−
a
)
∗
(
R
T
T
s
)
+
a
∗
R
T
T
RTTs = (1-a)*(RTTs)+a*RTT
RTTs=(1−a)∗(RTTs)+a∗RTT
其中,
0
<
=
a
<
1
0<=a<1
0<=a<1,RTTs随着a的增加更容易收到RTT的影响。超时时间RTO应该略大于RTTs,TCP的使用的超时时间计算如下:
R
T
O
=
R
T
T
s
+
4
∗
R
T
T
d
RTO = RTTs+4*RTTd
RTO=RTTs+4∗RTTd
其中,RTTd为偏差的加权平均值。