负责端到端通信服务(进程和进程之间的通信)
1. 端口号
-
IP地址找到不同网络下的目的网络 -> mac地址找到同一网络下的主机 -> 端口号找到对应主机的应用进程
-
端口用一个 16 位端口号进行标志,允许有65,535个不同的端口号。
-
端口号只是为了标志本计算机应用层中的各进程,不同计算机的相同端口号是没有联系的。
-
端口分类
- 熟知端口(系统端口):0-1023。FTP:21,TELNET:23,SMTP:25,DNS:53,TFTP:69,HTTP:80,SNMP:161,SNMP(trap):162,HTTPS:443
- 登记端口:1024-49151。比如微软开发了一个系统应用,该应用在通讯或使用时,需要使用到xxx端口,那么就要去登记一下这个端口,以免有别人公司的应用使用同一个端口号
- 客户端端口:49152-65535,又叫短暂端口号,用户进程选择暂时使用,通信结束后,就释放掉。
2. UDP(用户数据报协议)
- 无连接:在通讯之前不需要建立连接,直接传输数据。
- UDP使用尽最大努力交付;不保证可靠交付。
- UDP是面向报文的。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。也就是说,UDP一次交付一个完整的报文。
- UDP没有拥塞处理控制,因此网络出现的拥塞不会使源主机的发送速率降低。
- UDP支持一对一、一对多、多对一和多对多的交互通信。 UDP的首部开销小,只有8个字节,比TCP的20个字节的首部要短。
3. TCP(传输控制协议)
- TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。
- 应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接。
- 一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的(一对一)。
- TCP提供可靠交付的服务,也就是无差错、不丢失、不重复、按序到达。
- TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。
- TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。
- TCP根据堆放给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节,UDP发送的报文长度是应用程序给出的。
- TCP连接的端点叫做套接字(socket)或插口。套接字socket=(IP地址:端口号)。
- 每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定。即:
TCP连接::={socket1, socket2}={(IP1:port1),(IP2:port2)}
3.1 TCP报文头
- 序号字段(seq)——占 4 字节。TCP 连接中传送的数据流中的每一个字节都编上一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。
- 确认号字段(ack)——占 4 字节,是期望收到对方的下一个报文段的数据的第一个字节的序号。
- URG:紧急指针是否有效
- ACK::确认序号是否有效
- PSH:用来提示接收端应用程序立刻将数据从tcp缓冲区读走
- RST:要求重新建立连接. 我们把含有RST标识的报文称为复位报文段
- SYN:请求建立连接. 我们把含有SYN标识的报文称为同步报文段
- FIN:通知对端, 本端即将关闭. 我们把含有FIN标识的报文称为结束报文段
4. 可靠传输的工作原理
通过数据编号和积累确认、以字节为单位的滑动窗口、超时重传时间 、快速重传这四个方面来达到可靠传输的目的。
- 数据编号:将每个字节进行编号,有900个字节,就从1到900进行编号
- 积累确认:服务器端不是接收到一个字节就发一个确认,那样效率太低,而是当接收到4,5个时,在发送一个确认,那么在之前的确认之前的数据就算发送成功了的。
- 滑动窗口:这个跟在数据链路层讲个滑动窗口一样。每次能发送的数据是在此窗口中的,接到了多少数据,就往后滑多少数据
- 超时重传时间:这个也在链路层讲过,如果等待一段时间后,还没接收到确认报文,那么就重新传
- 快速重传:在滑动窗口中的应用,比如传了12346到服务器端,老办法是在4之后的所有数据度要重新传,而这个快速重传就只需要等待传了5这个序号,就可以继续往下接收数据了。
4.1 停止等待协议
- 出现差错,超时重传
- 自动重传请求ARQ
- B此时采取的两个行动:(1) 丢弃这个重复的分组M2,不向上层交付;(2) 向A发送确认。
4.2 流水线传输
停止等待协议的优点是简单,但缺点是信道利用率太低。
- 连续ARQ协议和滑动窗口协议
5. TCP可靠传输的实现
动态讲解:https://www.bilibili.com/video/BV1Tb411x7CE?p=119
重点:若收到的报文段无差错,只是未按序号,中间还缺少一些序号的数据,那么能否设法只传送缺少的数据而不重传已经正确到达接收方的数据?
选择确认 SACK (Selective ACK) 就是一种可行的处理方法。
6. TCP的流量控制
抑制发送端发送数据的速率,以使接收端来得及接收;
是点对点通信量的控制,是端到端的问题;
7. TCP的拥塞控制
-
拥塞:对资源的需求总和 > 可用资源
-
拥塞控制:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
-
进行拥塞控制的算法:
- 慢开始算法:由小到大逐渐增大发送窗口。(发送方让自己的发送窗口等于拥塞窗口)
- cwnd = 1,初始拥塞窗口为1,只能发送一个报文段。设置慢开始门限ssthresh
- 当拥塞窗口大小达到门限时,使用拥塞避免算法;
- 拥塞避免:每隔一个往返时间RTT,就让cwnd + 1
- 当出现超时时,判断为网络拥塞;设置拥塞窗口为1,调整门限为 cwnd / 2,重新慢开始、拥塞避免算法;
- 当发送方连续接收到3个对同一个报文段的重复确认时,发生了个别报文段的丢失,采用快恢复算法,调整门限为 cwnd / 2,并开始执行拥塞避免算法
8. TCP的三次握手
TCP建立连接的过程叫做握手,在通信之前,会先通过三次握手的机制来确认两端口之间的连接是否可用。而UDP不需要确认是否可用,直接传。
注:
- 序号 : seq
- 确认:ACK
- 确认序号:ack,我期待对方发送的数据包的序列号
- 同步 :SYN,SYN=1表示建立连接
阶段分析:
-
第一次握手:SYN=1,seq=x
- SYN = 1,客户端向服务器请求建立连接。TCP规定,SYN报文段不能携带数据,但消耗一个序号,随机选择一个初始序号seq = x。此时没有相应动作,与ACK无关。
- 发送完请求连接报文后,客户端的状态就变为了SYN_SENT,可以说这个状态是等待发送确认(为了发送第三次握手时的确认包)。
-
第二次握手:服务端接收到连接请求报文后,从LISTEN状态变为被动打开状态,然后给客户端返回一个报文。SYN = 1, ACK = 1,seq = y, ack = x +1
- 服务器端建立连接后做出确认响应:SYN = 1, ACK = 1
- SYN报文段不能携带数据,但消耗一个序号,随机选择一个初始序号seq=y。
- 因为到序号为x为止的所有数据都收到了,所有告诉客户端,期待序号为x+1 ,即 ack = x + 1
- 发完后,变为SYN_RCVD状态(也可以说是等待接受确认状态,接受客户端发过来的确认包)
-
第三次握手:客户端收到服务器端的确认和知道服务器端也已经准备好了连接后,还会发一个确认报文到服务器端,告诉服务器端,我接到了你发送的报文,同时发送向服务器端的数据,ACK = 1 ,seq = x + 1, ack = y+1
- 因为到序号为y为止的所有数据都收到了,所有告诉服务器端,期待序号为y+1 ,即 ack = y + 1
总结:起初A和B都处于CLOSED状态——B创建TCB,处于LISTEN状态,等待A请求——A创建TCB,发送连接请求(SYN=1,seq=x),进入SYN-SENT状态——B收到连接请求,向A发送确认(SYN=ACK=1,确认号ack=x+1,初始序号seq=y),进入SYN-RCVD状态——A收到B的确认后,给B发出确认(ACK=1,ack=y+1,seq=x+1),A进入ESTABLISHED状态——B收到A的确认后,进入ESTABLISHED状态
9. TCP的四次挥手
-
FIN:报文的终止控制位,FIN = 1表示要释放连接,FIN报文段即使不携带数据,也要消耗一个序号
-
第一次挥手:Client端发起中断连接请求,也就是发送FIN报文。并停止再发送数据,主动关闭TCP连接,进入FIN-WAIT-1(终止等待1)状态,等待B的确认。
- FIN = 1 ,seq = u,u 等于前面已传过的数据的最后一个字节的序号加1
-
第二次挥手:Server端接到FIN报文后发出确认ACK = 1,发出确认号ack = u+1, 告诉Client端此时的我的序号为v,seq = v , v 是服务器端前面已传送过的数据的最后一个字节的序号加1,
- 服务器端进入CLOSE-WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务器的连接释放。
- A收到B的确认后,进入FIN-WAIT-2(终止等待2)状态,等待B发出的连接释放报文段。
-
第三次挥手:若服务器端没有要向客户端发出的数据,B发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),B进入LAST-ACK(最后确认)状态,等待A的确认。seq = w : 服务器端可能又发了一些数据
-
第四次挥手:客户端收到服务器端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1)
- 客户端进入TIME-WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。
总结:起初A和B处于ESTABLISHED状态——A发出连接释放报文段并处于FIN-WAIT-1状态——B发出确认报文段且进入CLOSE-WAIT状态——A收到确认后,进入FIN-WAIT-2状态,等待B的连接释放报文段——B没有要向A发出的数据,B发出连接释放报文段且进入LAST-ACK状态——A发出确认报文段且进入TIME-WAIT状态——B收到确认报文段后进入CLOSED状态——A经过等待计时器时间2MSL后,进入CLOSED状态。
注:
- 为什么A还要发送一次确认呢?可以二次握手吗?
主要为了防止已失效的连接请求报文段突然又传送到了B,因而产生错误。
- 为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
- 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
参考博客:
https://www.cnblogs.com/Andya/p/7272462.html
https://www.2cto.com/kf/201709/680298.html