目录
有几个协议的模板,方便我们更好的设计应用层的协议
XML
基本格式:<开始标签名>内容结束标签名>
封装日期:2022-07-30,大概就是
可读性好,但是空间浪费大,运行效率不高
json
基本格式{键:值,键:值}
一个{}内可以有多个键值对,键和值之间使用冒号分隔,多个键值对使用逗号分隔,要求键是字符串类型
{USERID:1234,MANE:李四}
当使用json表示时,可能造成key的重复
{ {USERID:1234,MANE:李四},{USERID:1235,MANE:王五}}
protobuffer
一种二进制的数据,不再记录key值,而是提供一些符号和顺序来描述每一个二进制数据,同时通过一个IDL文件辅助记录
可能就是\1234\李四\1235\王五,将这些数据存储为二进制进行通信
传输层为它上面的应用层提供服务
传输层为应用进程之间提供通信(端口号)
传输层的两个协议:
用户数据报协议(UDP)
传输控制协议(TCP)
UDP在传输数据之前不需要建立连接,接收端的传输层接收到UDP报文之后,不需要给出任何确认,虽然UDP是不可靠传输,但是在某些情境下,UDP却是一种最有效的方式
源端口号:本机端口号,在对方回信时使用,不使用时可用全0
目的端口号:接收端端口号
数据长度:UDP数据报的长度,也就是(UDP首部+应用层数据)的长度
检验和:检验整个UDP数据报是否出错
1、无连接
2、不可靠:不存在任何的安全机制,数据发送失败是不会有任何提示的
3、面向数据报:应用层交给UDP多长的报文,UDP原样发送,不会拆分和合并
4、存在接收缓冲区
UDP没有真正意义上的发送缓冲区,数据直接就给内核
UDP存在接收缓冲区,但是不能保证接收顺序和发送顺序一致;如果接收缓冲区满了,以后的数据将被丢弃
5、全双工:可以读也可以写
6、大小受限:因为UDP的数据长度2字节,也就是64kb,当传输数据过大时,就会导致数据丢失
TCP是面向连接的协议,传输数据之前要建立连接,支持可靠传输,接收端的传输层接收到TCP报文之后,需要给出确认
TCP和UDP相比,要支持可靠传输和面向连接,就会增加开销
TCP会存在发送缓存和接收缓存
TCP首部包括两个部分:20字节的固定首部和选项及填充字段
选项:长度可变,最长可达40字节
填充:TCP希望首部是4字节的整数倍,用于在添加选项后补充长度
源端口和目的端口:都是两个字节
序号:占有4个字节。在一个TCP连接中的字节流的每一个字节都会按照顺序编号,这里的序号表示这个报文段发送数据的第一个字节的序号
确认号:占有4个字节,期望收到对方下一个报文段的第一个字节的序号,如果确认号是N,表示前N-1个数据传送成功
数据偏移:表示TCP首部的长度,也即是TCP报文数据部分到TCP数据报起始部分的距离;占4位,基本单位是4个字节,因为4个二进制位的最大数字是15,而基本单位是4字节,也即是60字节,也是TCP首部的最大长度
保留:占6位,保留为今后所用
窗口:占2字节,窗口是本报文段的接收窗口,窗口值告诉发送方,从本报文段确认号算起,可以接受的字节数,发送方就可以根据这个值,安排发送数据的多少
例如:B发送了一个应答报文,确认号是701,窗口字段是1000,就是告诉发送方,我可以从701号字节算起,最多接收1000个字节的数据,发送方就可以根据这个数据,安排下一个报文的数据长度
校验和:占有2字节;检验报文是否出错
紧急指针:两个字节;和URG搭配使用,指出本报文段的紧急数据的字节数
六个控制位
(1)无差错情况
A发送M1后暂停发送,等待B的确认。B收到了M1就向A发送确认,A收到了M1的确认之后,发送M2
(2)有差错情况
有差错情况就有两种原因:1、A给B发送的M1,B确实没收到2、B收到了A发送的M1,也发出来响应,但是A没收到B做出的回应
对于第一种,A就可以重新发送数据,对于第二种,B收到了数据,A可以继续发送M2,但是这两个情况发送方无法分别,TCP只能做好最坏的打算,也就是第一种情况,就需要重新发送数据,称为超时重传
在发送每一个数据时,都会设置一个超时计时器;只要A在超时计时器到期之前,收到了B的确认,就撤销超时计时器;A在超时计时器到期之后,仍收不到B的确认,就会重新发送该数据
这里要注意三点:
1、A发送完一个数据M1,就要暂时保留已经发送数据M1的副本,只有收到B的确认才可以删除副本,否则超时重传时就找不到M1内容了
2、分组和确认分组是要进行编号的,否则就无法知道是哪一个数据没收到确认
3、超时计时器的时长设置要合理
但是这样处理还有一个问题:
1、A给B发送的M1,B确实没收到2、B收到了A发送的M1,也发出来了响应,但是A没收到B做出的回应;这两个情况都进行超时重传,万一是情况2,就会将信息重新发出一次,B就会收到2次操作,这是不合理的
我们就要进行去重操作:
TCP会存在发送缓存和接收缓存
发送缓存:存放准备发送的数据和已经发送但是没有收到确定的数据
接收方收到的数据会放到操作系统内核的“接收缓冲区”中,收到新的数据,TCP会根据序号,检查这个数据是否已经存在于缓冲区中,如果存在就直接丢弃
连接建立:三次握手
连接断开:四次挥手
三次握手:客户端主动发起
三次握手本质是四次,只不过两个操作可以打包到一起
三次握手的意义:检测当前网络是否可以进行传输
就类似于下方的打电话:
A给B发连接请求:请求验证A的发送能力和B的接收能力
B给A发送响应:证明A的发送能力和B的接收能力都是好的,现在验证B的发送能力和A的接收能力
A给B做出响应:证明了B的发送能力和A的接受能力是好的
这三个过程,就可以证明客户端和服务器是可以正常进行通信的
四次挥手:客户端主动发起也可以是服务器主动发起
三次握手,让连接建立成功,就会在内存中占有空间,存放相关信息
断开连接:
提高速率的方式,同时传输一大批数据,同时接收ACK
以上讲的一传一应答的效率过慢:数据的往返时间越长,通信的效率就越低。
为解决这个问题,TCP 引入了滑动窗口这个概念。
有了窗口,就可以指定窗口大小,窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。
假如窗口大小是3,第一次就可以直接传入3个TCP的数据,只要收到一个ACK,就可以传入下一个数据
1、ACK丢失
2、SYN丢失
流量控制:让发送方慢一点,要让接收方来得及接收
在通信过程中,接收方根据缓存区的大小,通过报文段的窗口字段通知对方,以此来动态协调发送方缓存区的大小,从而协调控制发送方的发送速率
窗口字段:相当于告诉发送端,接收端缓冲区可继续容纳的大小;虽然这个字段只有64k的大小,但是TCP选项可以设置窗口扩大因子M,可以将实际大小左移M位
当窗口字段为0:发送端将无法继续发送数据,接收端将不断将缓冲区的数据提交给应用进程;但是发送端还是需要知道窗口大小的,发送端会周期性的发送探测报文,不会传输实际的数据,只是为了刺激发送方的ACK,得到窗口大小,只要窗口大小不是0,就可以继续发送数据了
拥塞控制宏观把控整个链路的情况;拥塞控制阻止过多的数据注入网络中,从而让网络中的路由器或者链路不至于过载
拥塞控制涉及到了所有的主机,所有的路由器,以及降低网络传输的所有因素;而流量控制是端到端的(接收端和发送端),动态调整发送方的传输速率
发送窗口=min(接收窗口,拥塞窗口)
接收窗口:接收方根据自己缓冲区可存储数据的大小,将数据交给发送方,发送方根据这个值调节发送缓冲区的大小
拥塞窗口:发送方根据当前网络的阻塞程度而设置的窗口值,反映当前网络可以通信的数据量
发送方如何知道当前网络阻塞了呢?
一旦网络发送了阻塞,数据过多,路由器就会丢包,放弃一部分数据;那么接收方就会收不到某些数据,从而发送方一直收不到这些数据的应答报文;会导致超时重传
而因为传输中间出现差错的可能性太小(远小于1%),因此:网络拥塞的依据就是超时
慢开始和拥塞避免
门限值:当门限值数据在16时,没丢包,但是如果继续指数增长,就可能造成丢包;所以在16之后,呈现线性增长,期待找到一个合适的窗口大小:在不丢包的前提下,尽可能运输的最大数据量
在②超时之后,立马降到1的原因:网络环境是复杂多变的,如果只是从24降低到23,难保23不会造成数据丢包,还不如降到1,虽然传输数据少,但是稳妥,减少对网络的影响
快重传和快恢复
在慢开始和拥塞避免中,如果只是数据丢失,网络并没有发送拥堵,接收方那么就会发出3个重复的ACK,这时仍然会导致超时重传,就会将窗口降为1,开始新一轮的慢开始;但是网络并没有拥堵,就会降低速率
快重传和快恢复:接收到3个重复的ACK,就会在超时计时器到来之前,执行快重传算法,重新发送数据,这样就不会导致超时,也就不会认为产生了网络阻塞
举一个例子:如果接收缓冲区大小1000k,接受了500k的数据,如果立即返回ACK,我返回的窗口大小就是500k,意味着发送方还可以给我发送500k的数据;但是这期间接收方如果把数据消耗完了,发送的500k数据就有点少了;延时应答就是指稍稍等一会在应答,就可以返回比500k大的数字,这时发送缓冲区就可以安排发送更多的数据
因为延时应答的存在,导致以下结果
TCP是面向字节流的,主机A发送两个TCP,分别为aaa和bbb,主机B对数据进行解析,应用层得到的数据是字节,也就是aaabbb,那么B的应用层是如何将数据分割开来的
TCP没有长度字段,B的应用层是如何将数据分割开来的:应用层要给包之间加边界,用于分割数据
UDP:UDP有长度字段,同时,UDP是面向数据报的,数据是按照一个一个的数据报进行传输的,不会分隔不开
1、突然关闭进程:TCP是通过Socket来进行通信的,Socket本质是进程打开的一个文件,而进程的PCB里会存在一张文件描述符表,用于管理文件
关闭进程,那么PCB就不在了,文件描述符表也就没了,Socket也就没了,相当于自动关闭(用户代码调用close(),四次挥手)
2、电脑关机
电脑正常关机,操作系统会关闭所有进程,进入第一种情况
3、网线断开\电脑突然断电
操作系统反应不过来,不会关闭进程
如果服务器断电:客户端发送的数据收不到ACK,那么就会尝试重传,重传几次失败后就会尝试重新连接,连接失败就会放弃连接
如果客户端断电:服务器接收不到客户端的数据,但是服务器不知道客户端是暂时不传消息,还是出现了故障;服务器就会周期性发送探测报文,用于触发客户端的ACK,收不到ACK,那么就会尝试重传探测报文,重传几次失败后就会尝试重新连接,连接失败就会放弃连接(设置保活计时器,服务器每收到一次客户端的消息,就重置保活计数器,时长2小时,保活计时器到期之后,服务器每隔75s发送探测报文,连发十次之后仍无客户端反应,就认为客户端故障)