传输层协议:负责数据能够从发送端传输接收端。
1.UDP协议
1.1 UDP协议端格式
UDP报头: 对于UDP报头,大多数资料上给出的都是这种形式: 但这其实是为了排版方便才这样描述的,真正的UDP报头应该是如下形式:
- 16位(bit位)UDP长度,表示整个数据报(UDP首部+UDP数据)的最大长度;
- 如果校验和出错,就会直接丢弃;
1.2 UDP的特点
UDP传输的过程类似于寄信
-
无连接 知道对端的IP和端口号就直接进行传输,不需要建立连接; -
不可靠 没有任何安全机制,发送端发送数据报以后,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息; -
面向数据报 应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并;
用UDP传输100个字节的数据: 如果发送端一次发送100个字节,那么接收端也必须一次接收100个字节;而不能循环接收10次, 每次接收10个字节。
-
缓冲区 UDP只有接收缓冲区,没有发送缓冲区: UDP没有真正意义上的 发送缓冲区。发送的数据会直接交给内核,由内核将数据传给网络层协议 进行后续的传输动作; UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一 致;如果缓冲区满了,再到达的UDP数据就会被丢弃; -
全双工 UDP的socket既能读,也能写 -
大小受限 UDP协议首部中有一个16位的最大长度。也就是说一个UDP能传输的数据最大长度是64K(包含UDP首 部)
1.3 基于UDP的应用层协议
- NFS:网络文件系统
- TFTP:简单文件传输协议
- DHCP:动态主机配置协议
- BOOTP:启动协议(用于无盘设备启动)
- DNS:域名解析协议
- 当然,也包括你自己写UDP程序时自定义的应用层协议。
2. TCP协议
2.1 TCP协议端格式
- 源/目的端口号:表示数据是从哪个进程来,到哪个进程去;
- 32位序号/32位确认号:基于TCP协议是可靠传输,用于确认数据是否传输到接收方
- 4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是
15 * 4 = 60 - 6位标志位:
URG:紧急指针是否有效 ACK:确认号是否有效 PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走 RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段 SYN:请求建立连接;我们把携带SYN标识的称为同步报文段 FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段 - 16位窗口大小:
- 16位校验和:发送端填充,CRC校验。接收端校验不通过,则认为数据有问题。此处的检验和不
光包含TCP首部,也包含TCP数据部分。 - 16位紧急指针:标识哪部分数据是紧急数据;
- 40字节头部选项:暂时忽略;
2.2 TCP原理
TCP对数据传输提供的管控机制,主要体现在两个方面:安全和效率。 这些机制和多线程的设计原则类似:保证数据传输安全的前提下,尽可能的提高传输效率。
2.2.1 确认应答机制(安全机制)
TCP将每个字节的数据都进行了编号。即为序列号。(以字节为单位对数据进行编号) 每一个ACK都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据;下一次你从哪里开 始发
2.1.2 超时重传机制(安全机制)
- 主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B;
- 如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发;
但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了; 因此主机B会收到很多重复数据。那么TCP协议需要能够识别出那些包是重复的包,并且把重复的丢弃 掉。
这时候我们可以利用前面提到的序列号,就可以很容易做到去重的效果。
2.1.3 连接管理机制(安全机制)
在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接
- syn是该协议中的一个标志位。如果该位被置为1,则表示这个报文是一个请求建立连接的报文(同步报文段)。
- ack也是该协议的一个标志位。如果该位被置为1,则表示这个报文是一个用于确认的报文(确认报文段)。
- 如果ACK这一位是1,表示这个报文段就是一个“确认报文段”
三次握手建立连接:
这个过程是一个双向奔赴的过程,类似于表白,双方都像对方表白,才算真正建立了关系
而且,中间的这两次(ACK+SYN)是会合二为一的,因为每次要传输的数据,都要经过一系列的封装和分用,才能完成传输,为了提高传输的效率,这里会把二次封装合为一次封装发送
这个过程也很容易,在tcp报文段中同时将SYN+ACK设置为1进行传输即可: 所以三次握手建立连接就是这样: 对于TCP的状态,很多我们是不需要也没必要去关注的,我们只需要知道这两个即可:
- LISTEN:表示服务器启动成功,端口绑定成功,随时可以有客服端来建立连接(类似于手机开机,信号良好,随时可以有人打电话过来)
- ESTABLISHED:表示客服端已经连接成功,随时可以进行通信了(类似于电话接通,随时可以说话了)
四次挥手断开连接: 三次握手,就让客服端和服务器之间建立好了连接;建立好了连接之后,操作系统内核中,就需要使用一定的数据结构来保存连接相关的信息;其中保存的信息其实最重要的就是“五元组”,并且客服端服务器都得保存五元组~ (源IP+源端口+目的IP+目的端口+协议(TCP/UDP)),既然保存了信息就需要占用系统资源(内存),如果之后连接断开了(连接不复存在了),此前保存的连接信息就没有意义了,对应的空间也就可以释放了;
四次挥手断开连接图示: 双方各自向对方发生了FIN(结束报文段)请求,并且各自给对方一个ACK确认报文; FIN设置为1,就表示这是一个结束报文段
- 三次握手,一定是客服端主动发起的(主动发起的一方才叫客服端)
- 四次挥手,可能是客服端主动发起的,也可能是服务器主动发起的
- 三次挥手,中间两次能合并
- 四次挥手,中间两次有时候合并不了(有时候是能合并的),不能合并的原因,在于B发生ACK和B发生FIN的时机是不同的;四次挥手中,B给A发生的ACK,是操作系统内核负责的,B给A发的FIN是用户代码负责(B中的代码调用了socket.close()方法,才会触发FIN,收到FIN,内核立刻返回ACK)
- 而三次握手建立连接中,B发送的ACK和SYN是同一时机的,就能够合并,此时B给A发送的ACK和SYN都是由操作系统内核负责进行的
对于断开连接中的状态,有两个需要我们重点理解:
-
CLOSE_WAIT :四次挥手了两次之后出现的状态,这个状态就是在等待代码中调用socket.close()方法,来进行后续的挥手过程;正常情况下,一个服务器上不应该存在大量的CLOSE_WAIT,如果存在,大概率是代码bug,close没有被执行到 -
TIME_WAIT:谁主动发起FIN,谁就进入到TIME_WAIT,起到的效果,就是给最后一次ACK提供重传的机会 因为表面上看起来,A发送完ACK之后,就没有A啥事了,按理说,A就应该销毁连接,释放资源,但是实际情况A并没有直接释放,而是会进入到TIME_WAIT状态等待一段时间,再来释放连接(等待这一个过程,就是担心最后一个ACK丢包,如果最后一个ACK丢包了,就意味着B过一会就会重传FIN) -
TIME_WAIT的持续设定时间一般是2*MSL(MSL表示网络上任意两点之间,传输需要的最大时间,这个时间也是系统上可以自行配置的参数,一个典型的设置就是60s(经验值))
|