传输层:负责端与端之间的传输(端:端口,端点)
udp协议的特性:无连接、不可靠、面向数据报
(1)无连接:UDP客户端给服务端发送消息的时候,不需要和服务端先建立连接,直接发送(客户端也不清楚服务端是否真正在线)
(2)不可靠:UDP并不会保证数据是可靠有序到达对端
(3)面向数据报:UDP数据不管是和应用层还是网络层,都是整条数据交付
(1)16位源端口号:当前的udp数据从哪一个进程产生
(2)16位目的端口号:当前的udp数据去往哪一个进程
(3)16位udp长度:udp数据的最大传输数据大小
常问问题:
(4)16位udp校验和:校验数据在传输的过程当中是否失真
失真了:udp协议就会将该udp数据报丢弃
没有失真:当应用层调用recvfrom函数的时候,就会将udp数据给到应用层
(1)发送缓冲区:将应用层提交给传输层的数据打上udp报头后就提交给网络层继续传输
(2)接收缓冲区:去掉udp报头之后,将数据递交给应用层。udp并不保证数据的可靠以及有序。
(1)DNS:域名解析
(2)DHCP:动态主机分配协议,谁上网给谁分配ip
(3)同一个局域网内部可能使用UDP,因为网络稳定
(4)NFS:网络文件系统
TCP协议:面向连接、可靠传输、面向字节流
(1)面向连接:双方在发送网络数据之前必须先建立连接,再进行发送
(2)可靠传输:保证数据是可靠并且有序的到达对端
(3)面向字节流:多次发送的数据在网络传输过程当中没有明显的数据边界。比如先发123,再发456,另一端收到的就是123456,它没有间隔。
win:wireshark针对网卡进行抓包
Linux:tcpdump:可以抓任意协议的数据包,并不是只能抓tcp
命令范式:tcpdump -i any port [端口] -s 0 -w [命名的文件]
port [端口]:是可选项,如果不加做则没有使用端口进行过滤,则抓取出来的数据包会比较大
命名的文件:例如123.dat
将抓出来的文件通过wireshark进行分析
注意:想要看到三次握手的过程,需要先开启抓包,再启动程序。
只有“主动断开连接方”才会存在TIME_WAIT状态
MSL:报文最大生存时间
自发送方发送出去之后,发送方认为该报文的最大生存时间是MSL
2MSL:ACK数据的MSL+被动断开连接方重传的FIN报文
重传的情况:(1)FIN报文还未到达被动断开连接方就丢失了
(2)主动断开连接方回复的ACK报文丢失
如果等待了2MSL的时间,也没有等到重传的FIN报文,则说明ACK数据一定到达了被动断开连接方
服务端处于TIME_WAIT状态会引发什么样的问题?
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
listenfd:套接字描述符
SOL_SOCKET:套接字选项
SO_REUSEADDR:重用端口
1.被动断开连接方才会存在的状态
2.处于CLOSE_WAIT状态的一方需要调用close函数关闭新连接的套接字。
被动断开连接方如果有大量的连接都处于CLOSE_WAIT状态,那需要检查代码中是否有阻塞,循环 导致被动断开连接方无法调用到close
在CLOSE_WAIT到LAST_ACK中,需要被动断开连接方调用close函数。
(1)16位源端口号:当前的tcp数据从哪一个进程产生
(2)16位目的端口号:当前的tcp数据去往哪一个进程
(3)32位序号:用来标识tcp数据的起始序号
(4)32位确认序号:ack,告知对端,自己期望对端下一次发送数据的时候,从哪一个序号开始
(5)4位首部长度:最大为:1111 --》 15
计算出来的是一个数值,并不是字节
首部长度占用字节数量 = 4位首部长度计算出来的数值 * 4
1111 --》 15 * 4 = 60字节
tcp头部最大为60字节,最小为20字节
URG:紧急标志位(MSG_OOB:紧急数据,带外数据)
ACK:确认标志位
PSH:发送数据标志位
RST:重置连接标志位
SYN:发起连接标志位
FIN:断开连接标志位
(6)16位窗口大小:牵扯到滑动窗口机制
(7)16位校验和:判断TCP数据在传输过程中是否失真
(8)16位紧急指针:配置URG标志位一起使用,传输紧急数据
(9)选项:MSS:最大报文段长度
MSS:最大报文段长度
TCP双方在三次握手过程中协商最大报文长度的大小
客户端 --》服务端:MSS_cli
服务端 --》客户端:MSS_svr
采用双方最小的MSS,作为后续传输数据的最大报文段长度,min(MSS_cli , MSS_svr)
作用:
TCP在传输数据的时候,严格按照MSS进行传输
MSS的大小和本地的网卡息息相关
MSS + ipheader + tcpheader <= MTU
MSS一定是小于MTU
MTU:最大传输单元(数据链路层对网络数据的限制)
命令:ifconfig
TCP在每一次发送数据的时候,数据的大小都不会超过MSS
只有TCP有MSS的限制,UDP是没有的(unit16_t)!!!
当发送方发送了一个数据之后,就会开启一个重传计时器,当重传计时器记录的时间超过重传时间,则重传该报文
超时重传时间是固定的吗?
不是的
RTO:超时重传时间
RTT:报文往返时间
TRO:2 * RTT
RTT(预测本次数据包的报文往返时间)=RTT(prev)* 0.9 + RTT(prev)* 0.1
考虑到提高发送方发送的速率,接收方暂时不应答,允许发送方一次性发送多个分组到网络当中。
如果收到了后面分组的确认应答,但是没有收到前面分组的确认应答,则窗口不能向后滑动,防止前面分组在网络当中丢失掉了,需要进行重传。
滑动窗口:允许一次性丢到网络当中分组的集合,分组的个数就是窗口的大小
发送方窗口大小是动态变化的,取决于接收方通告的窗口大小
(1)丢失某个分组的ACK
当窗口当中某个分组的ACK丢失之后,可以通过收到的高确认序列号,来确认丢失ACK的分组数据都达到对端,从而不需要重传。
(2)丢失某个分组数据
如果数据丢失,一定要重传!!!
TCP通过协议字段中的"窗口大小"字段来控制双方发送数据的数据量
如果对双方的发送数据的量不加以控制,则有可能导致接收方由于接收能力不足,而将发送方发送的数据丢弃掉,触发发送方进行重传,如此往复,网络当中就会充斥着大量的重传数据包,占用宽带资源。导致整个网络的转发能力变差。
(1)发送方主动给接收方发送窗口探测包
询问接收方的接受能力,注意:窗口探测包的数据的大小为固定的1字节
(2)接收方主动给发送方发送窗口更新通知
作用TCP的双方对发送数据的速率(提高了TCP的发送速率)
需要考虑的问题:一开始就要按照滑动窗口的大小,发送数据吗?
否,没有考虑到网络的转发能力是否能够满足一次性传输窗口大小的数据
拥塞控制机制:本质也是在控制发送方发送数据的量
最终发送的数据量:min(发送方的滑动窗口大小,拥塞控制机制当中的拥塞窗口大小)
发送方的滑动窗口大小取决于接收方的接收能力
拥塞控制机制当中的拥塞窗口大小取决于网络拥塞程度
慢启动:TCP通信双方,在建立连接之后,先发送少量的数据(拥塞窗口的数据),探测网络的转发能力(根据TCP数据的往返时间),根据网络转发能力,主动调整拥塞窗口大小。
拥塞窗口的大小为1个分组(1个MSS)
慢启动:拥塞窗口的大小,随着传输轮次的增加,拥塞窗口呈现指数增长
慢开始门限:ssthresh的初始值
在拥塞窗口大小小于慢开始门限的时候,是呈指数增长
当拥塞窗口的大小超过慢开始门限,则转换位拥塞避免算法
拥塞避免:随着传输轮次的增加,拥塞窗口的大小呈线性增长(一次增加1个分组)
(1)早期TCP发现网络拥塞之后,是将拥塞窗口调整为1(即1个分组),从慢开始重新增长拥塞窗口大小,重新调整慢开始门限。
(2)现在TCP的做法:快恢复。一旦发现网络阻塞,择机算新的慢开始门限,从新的慢开始门限执行拥塞避免算法。
快重传:当发送方发送的网络数据丢包之后,发送方还没有触发超时重传机制的时候,有接收方快速的确认丢失报文的起始序号,告知发送方该报文丢失,则发送方不需要等到超时之后才重传。
延时发送机制:NAGLE算法,如果当前发送方存在少量的数据需要发送,则稍微的等待一会,等待数据量变大之后,再统一进行发送。
捎带应答机制:应用于双方都想给对方发送数据的场景,快速的进行交互,就将ack放到PSH数据包当中携带给对方。
延时应答机制:接收方接收到了数据,为了给消息发送方通告更大的窗口大小,等待一段时间,如果在这段时间内,应用层将数据从接收缓冲区当中接收走之后(recv函数),接收方在恢复确认的时候,就可以给发送方通告更大的窗口大小了。
心跳机制:判断空闲连接的双方是否是正常状态
在连接空闲的时候,就会启动一个保活计时器,记录连接空闲的时间,一旦当连接的空闲时间超过2小时,则主机B的TCP协议会主动给主机A发送保活探测包(心跳包)
如果主机B一直没有收到探测包的应答,则会每隔75秒发送一次,总共发送10次。
如果10次探测包都没有应答,则认为对端已经处于不正常的状态,则主动断开连接。
如果有应答,则认为连接正常。重新启动保活计时器进行计时。
从发送数据的角度理解:应用层的应用程序在发送数据的时候,是调用send函数将应用层数据递交给传输层的TCP协议。递交给TCP协议之后,数据是暂时保存在发送缓冲区当中。
TCP发送数据一定是小于MSS,有自己发送数据的规律。
从接收的角度来思考:当数据到达接收方的接收缓冲区之后,接收方的应用程序调用recv函数可以接受任意字节。
面向字节流服务会导致数据之间没有明显的边界,会导致TCP粘包问题
tcp服务端没有办法针对tcp数据进行拆分,拆分成不同的请求。比如发个12+12,24+24,可能收到12+1224+24,因为tcp是面向字节流的,数据之间并没有明显的间隔,就导致服务端无法拆分数据。
解决:
定义应用层自己的协议数据结构,来描述发送到数据
应用层头部+应用层数据+间隔符(\r\n)
每条数据都会由一个分隔符(\r\n),来间隔前后的两条数据
序列化:将对象转化成为二进制数据
反序列化:将二进制数据转化为对象
json是一种key/value的数据结构,可以支持嵌套定义,也可以支持多种基础类型(int,string,char),同同时也支持将json对象序列化成为二进制序列也可以将二进制反序列成为json对象