文章目录
1. 传输层协议UDP和TCP
TCP 与UDP协议的作用范围提供进程间的逻辑通信
而IP协议的作用范围提供主机间的逻辑通信。
TCP/IP协议栈
TCP:传输控制协议。一个数据包分段传输,并且每段编号,服务器和客户端之间建立关联会话,并且可以做流量控制,可靠性传输,面向字节流传输
UDP:用户数据包协议。**一个数据包就可以完成数据通信,不需要建立会话,不需要流量控制,不可靠传输,UDP首部开销小,只有8个字节。**比如DNS解析ip地址,多播或者广播
1. 传输层协议和应用层协议关系
常见应用层协议使用的端口:
http = TCP + 80
https = TCP + 443
RDP = TCP + 3389
ftp = TCP + 21
共享文件夹 = TCP +445
SMTP = TCP + 25
telnet = TCP + 23
DNS = UPD + 53
2. 服务和应用层协议的关系
服务器利用TCP或者UDP的端口侦听客户端请求,而客户端使用IP地址定位服务器使用,使用目标端口定位服务。
协议+端口
3. TCP协议
1. 端口
端口号只具有本地意义,端口号只是为了标志计算机应用层中的各个进程,*比如编码中经常出现的端口冲突,就是应用两个进程都占用一个端口。*一般是16位二进制表示。范围为[0,65535]
通信方式是通过:IP地址+端口(套接字)
4. UPD结构
3. TCP实现可靠传输
3.1 停止等待协议
设置一定的时间,一旦特定的时间没有收到,则重试发送。
超时重传
3.2 确实丢失和确认迟到
确认丢失:发送的数据一旦没有接受到数据时,则会重新发送,将第一个数据丢弃。
确认迟到:比如第一次发送的数据在特定的时间没有准确到达,过了很久才到达,则这种数据会丢失,利用已经准时获取的数据。
3.3 流水线传输
为了增加信道利用率,则发送方需要连续发送多个分组,不必每发送一组数据停顿下来等待接收方确认。
如何确认每次发送的数据量呢?
利用滑动窗口的方式,每次发送的数据必须在窗口里面。
3.3 TCP报文段首部
首部格式分为两部分:固定首部(20个字节)和可变部分
1. 固定首部
- 源端口:2个字节(16位)
- 目标端口:2个字节
- 序号:用于表示每个数据段的序号,因为数据包是分段传输的。该部分4个字节。
- 确认号:接收方给发送方的回馈,比如接收到了第5个字节,下一次需要发送第6个字节过来,表示发送方下一次要发送的起始字节,该部分4个字节。
- 数据偏移:表示TCP报文段真正有数据的位置。该部分有4位。该位置每个bit表示4个字节。
- 保留:6位二进制。
- URG:urgent,当
URG =1
时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。 - ACK ——
Acknowledgment
,请求确认的标志。只有当ACK = 1
时确认号字段才有效。当ACK = 0
时,确认号无效。 发送端向接收端发送连接请求是ACK = 0
,接收端同意发送端的请求,ACK = 1
。 - SYN —— 同步
SYN = 1
表示这是一个连接请求,比如发送端给接收端请求是,SYN = 1
;接收端给发送端返回同意请求连接时,SYN = 0
- PUSH:接收 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。
- RST:当 RST = 1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
- 终止 FIN (FINis) :用来释放一个连接。FIN = 1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接
- 窗口:占用两个字节。用来让对方设置发送窗口的依据,单位为字节。
- 校验和:占 2 字节。检验和字段检验的范围包括首部和数据两部分。在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。
- 紧急指针:占 16 位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)
- 长度可变:TCP 报文段中的数据字段的最大长度(MSS)。数据字段加上 TCP 首部才等于整个的 TCP 报文段TCP 最初只规定了一种选项,即最大报文段长度 MSS。该部分如果不够4个字节,则会用填充部分填充。
3.4 滑动窗口
使用滑动窗口的方式实现可靠传输。
利用滑动窗口技术发送和接收数据的方式如下:
以下用A表示发送方、B表示接收方。
首先说一下正常的发送接收情况,也就说不存在数据丢失情况。
1、发送方和接收方在缓存中发送和确认数据,第一步如下
2、A发送第一个片段后,不需要等待第一个数据段返回确认,就可以发送第二段数据。一旦B给A返回了接收确认时,A的发送缓存部分会右移,发送缓存中不断的添加新的数据片段。
3、 B再次受到A的确认数据回答时,将B的滑动窗口右移。并且过段时间会将已经确认接收的数据从A、B缓存中删除,
给数据的发送提供更多的缓存空间,
4、滑动窗口如此循环发送,直到所有的数据都发送完毕。A、B结构如下。
5、 上述情况都是理想情况下,也就是说不存在丢包现象,万一中途有一个数据包丢失时,接收端给发送端返回连续接收的部分。
并且如果特定的时间段没有收到接收确认,也会再次重传。超时重传的时间 大于加权平均的往返时间。
接收端会给发送端发送数据包序号44以前的都接收到了,但是47-49字节也接收到了,需要再次发送中间缺失的45、46部分。
4. TCP流量控制
让发送方的发送速率不要太快,既要让接收方来得及接收,也不要使网络发生拥塞。
目前是通过不断调节接收端的滑动窗口的大小来调节发送端的发送数据包大小。
5. TCP的拥塞控制
出现阻塞的情况:对资源的需求总和 > 可用资源
若网络中有许多资源同时产生拥塞,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降。
拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。
吞吐量模型如下图所示:
有了拥塞控制之后,不会出现完全不可用状态。
在实际的数据包发送过程中,是通过慢开始算法进行数据包的传输:
并不是第一次就发送很多数据包,而是逐步递增的。
慢开始算法设置了一个慢开始门限(默认是16),在该值之前的滑动窗口大小通过指数的方式增加,超过该值之后,会逐步递增。
达到一定值是,可能会开始丢包现象,这种说明开始出现了拥塞情况,会重新计算一个慢开始门限,该值是上次最大值的一半。
慢开始门限的初始值设置为 16 个报文段,
即 ssthresh = 16。第二次的慢开始门限为上次最大值一半
6. TCP的传输连接管理
传输连接有三个阶段:连接建立、数据传送、连接释放。
TCP 连接的建立都是采用客户服务器方式。
- 主动发起连接建立的应用进程叫做客户(client)。
- 被动等待连接建立的应用进程叫做服务器(server)
6.1 三次握手建立连接
1、第一次客户端主动给服务器发送一个连接的请求。其中SYN = 1
(表示是建立连接请求) ACK = 0
(只有返回确认是才是1) seq = x
(开始发送数据的序列号,x是一个代指)
2、服务器收到连接请求时,服务器给客户端返回确认结果,SYN = 1
(表示是建立连接请求) ACK = 1
(服务器给客户端返回) seq = y
(表示接受到的数据包的序号,因为传输层是分片段发送) ack = x + 1
(服务器收到了x个字节,需要客户端下次发送x+1
个字节)
3、客户端收到服务器的确认时,再次给服务器发送数据包。ACK = 1(表示客户端给服务器返回),seq = x+1
(数据包的序号),ack = y+1
,(告诉服务器下次该发y+1的序号)
问题:为什么需要三次握手,而不是两次握手呢?
试想一下,客户端第一次请求时,如果网络出现异常或者波动,请求迟迟没有到达服务器;客户端重新发送了一次请求,这次服务器正常接收到,服务器给客户端返回了请求响应,然后继续传送数据;过段时间后,第一次请求姗姗来迟,服务器仍然给客户端返回的请求响应,客户端接收到该响应之后,不会继续处理,然后服务器会一直等待,这样就会影响服务器的资源。但是三次握手就不存在这种情况了,会重复确认。
三次握手时各个阶段的客户端和服务器的状态:
1、客户端发送连接请求是,状态会变成SYNSENT
,服务器在接收到第一次握手的请求后,将状态由原来的LISTE
改成SYN-RCVD
2、服务器给客户端发送请求响应,客户端收到响应之后状态会变成ESTABLISHED
,然后继续给服务器再次确认。
3、服务器再次受到确认答复之后,会将服务器状态由SYN-RCVD
改成ESTABLISHED
。
4、三次握手完成之后,才开始进行数据传输。
6.2 连接释放
在建立连接,发送完数据之后,客户端和服务器间需要断开连接,通过四次挥手的方式实现。
过程如下:
1、客户端将所有的数据全部传送给服务器之后,先向服务器发出连接释放报文段,并停止再发送数据,主动关闭TCP连接。FIN = 1
(表示这是一次断开的请求)seq = u
,(数据包的序号为u),等待 服务器确认。
2、服务器发送确认,ACK = 1
(响应的请求), seq = v
(数据包序号), ack= u + 1
(数据包确认号),从 客户端到 服务器这个方向的连接就释放了,TCP 连接处于半关闭状态。服务器若发送数据,客户端仍要接收。(这种情况,客户端只接收,不发送)
3、服务器开始告诉客户端,我要关闭了。FIN = 1
(表示释放连接的), ACK = 1
(表示响应的请求), seq = w
(数据包序列号), ack= u + 1
(数据包确认号)
4、客户端收到服务器的释放请求,开始给服务器响应结果。ACK = 1
, seq = u + 1
(本次数据包序列号), ack = w + 1
(数据包确认号,表示已经收到w之前的数据)。
整个过程如下:
释放时,各个阶段的状态如下:
下面用A表示客户端、B表示服务器。
1、A没有给B发送释放请求之前,A、B都是出于ESTABLISHEN
,表示双方还是出于建立连接状态。
2、A给B发送释放请求时,A的状态会变成FIN-WAIT-1
,在没有得到B的请求响应之前,状态都是FIN-WAIT-1
,此时B还是ESTABLISHEN
状态。
3、A收到B的相应之后,A的状态会由FIN-WAIT-1
变成FIN-WAIT-2
,此时B会变成CLOSE-WAIT
,等待关闭。此时客户端 ——> 服务器已经关闭,服务器 ——> 客户端仍然处于连接状态。
4、B会开始断开与客户端的连接。B给A发送释放连接的请求,B状态会变成LAST-ACK
(最后一次确认)。
5、A会处理本次释放请求,给B响应结果。发送之后,A不会立刻关闭,而是变成TIME-WAIT
等待关闭。
6、等待一个时间段之后,B往A方向连接会正常关闭,客户端和服务器都会变成CLOSE
状态。
TIME-WAIT
阶段会等待2MSL时间段(MSL:一个请求的往返时间,默认为两分钟),为什么会等待该时间段呢?
因为担心A给B的释放请求响应的数据包丢失,过段时间后,B会再次发送释放请求,如果A即可关闭,则该请求不会再被处理,B会一直处于等待状态(资源浪费);等待2MSL之后,即使第一次丢包,下次请求仍然会正常处理,不会让B一直处于等待状态。