2022/8/9
TCP/IP模型 四层协议下——传输层 = 连接传输和无连接传输;网络层=无连接;
OSI open System interconnection 开放系统互联,七层模型下,传输层 = 无连接,网络层 = 连接 和 无连接 的;
因为经过三次握手,客户端与服务端才可以互相知道彼此收发数据包是否正常。
名称 | 说明 | 介绍 |
---|---|---|
第一次握手 | 客户端发送网络包,服务端接收到 | 服务端得出结论:客户端发送能力、服务端接收能力正常 |
第二次握手 | 服务端发送网络包,客户端接收到 | 客户端得出结论:服务端的接收、发送能力正常,客户端的发送、接收能力正常; 此时服务器并不能确定客户端的接收能力是否正常 |
第三次挥手 | 客户端发包,服务端收到 可携带数据 |
此时服务端可知:客户端的发送、接收能力正常,服务端的发送、接收能力正常 |
TCP是四次挥手,采用三次是不可以的(默认省略的是第二次握手)。
TCP是可以双向数据传输,也就是全双工协议;因此每个方向都需要自主发送FIN请求报文段和ACK确认报文段。
客户端发送FIN连接断开请求报文段,服务端回以确认报文段ACK,表示结束客户端向服务端的数据发送连接;
此时可能服务端有数据发送给客户端,故等待一段时间,直到服务端数据发送结束;
服务端发送断开请求确认报文段给客户端,其中FIN =1,ACK = 1 序列号seq = w 确认号ack = u+1;
客户端接收到服务端发送的断开连接请求后,发送确认报文段,标志位ACK = 1 序列号seq = u+1 确认号ack = w+1;
保证客户端发送的最后一个ACK服务端可以正常接收
等待2MSL(Maximum Segment Lifetime,报文最大生存时间)用于确认服务端是否收到客户端发送的确认释放连接的请求(ACK),在2MSL内,如果服务端又重新发送了释放连接请求报文(FIN+ACK),那么说明上一条客户端发送的确认报文(ACK)服务端没有收到。
如果客户端不等待2MSL时间,而是发送完ACK就直接释放连接,那么就会收不到服务端重新发送的释放连接请求(FIN+ACK)。
防止已失效的连接请求报文段出现在本连接中
客户端发送完最后一个ACK报文段后,等待2MSL,就可以使本连接持续时间内产生的所有报文段都从本网络中消失;
从而保证下一个连接中不会出现旧的请求报文段;
TCP与UDP区别:
区别 | TCP(Transmission Control Protocol) 传输控制协议 |
UDP(User Datagram Protocol) 用户数据包协议 |
---|---|---|
连接 | 面向连接 | 无连接 |
通信 | 可靠全双工通信 | 半双工通信 |
传输 | 可靠传输 | 不可靠传输 |
传输速度 | 相对较慢 | 相对较快 |
传输控制 | 有流量控制和阻塞控制 | 没有 网络出现阻塞不会使源主机的发送速率降低 |
服务对象 | 点对点 | 支持多模式:一对一、一对多、多对一、多对多 |
数据 | 面向字节流 | 面向报文 |
数据有序性 | 保证数据有序性 | 不保证数据有序性 |
数据边界 | 不保留数据边界 | 保留数据边界 指的是对应用层交付下来的报文不拆分、不合并保留原报文的边界 |
协议类型 | 重量级协议 | 轻量级协议 |
首部开销 | 协议首部20字节 | 协议首部8字节 |
应用场景:
协议 | 说明 | 案例 |
---|---|---|
TCP | 效率要求较低,准确率要求较高。 因为传输中需要对数据确认、重发、排序等操作,相比之下效率没有UDP高 |
文件传输、接收邮件、远程登录 |
UDP | 效率要求较高,准确率要求较低。 | qq聊天、在线视频、网络语音电话(及时通讯、速度要求高)、广播通信(广播、多播) |
概念 | TCP | UDP |
---|---|---|
连接 | 面向连接的传输层协议,双方通信前必须建立连接 三次握手-连接建立过程、四次挥手-连接释放过程 |
无连接传输协议 |
通信模式 | 每条TCP连接只能有两个端点(两个套接字socket),只能是点对点 | 支持一对一、一对多、多对一、多对多的交互通信 |
可靠交付 | 提供可靠交付的服务,数据传输无差别、不丢失、不重复、按序到达 | 使用最大努力交付的服务,不保证可靠交付 |
传输数据 | 面向字节流,不保证接收方收到的数据块和发送方发送的数据块具有对应大小的关系 即发送方可能发送10个数据块,接收方使用4个数据块就将字节流交付给上层的应用程序 |
面向报文,对应用层交下来的报文不合并、不拆出,保留边界 |
通信方式 | 全双工通信,允许通信双方的进程在任何时候都能发送数据 两端都有发送缓存和接收缓存,用来存放通信双方的数据 |
半双工通信, 双向传送数据,某一个时刻,只能一方为发送端,另一方为接收端 |
报文段首部 | 首部开销较大,20字节 | 首部开销较小,8字节 |
拥塞控制 | 有拥塞控制,为了防止数据大量涌入网络,造成路由或链路过载 | 没有拥塞控制,网络出现拥塞不会使源主机的发送速率降低 |
TCP | UDP |
---|---|
FTP(21) file transfer protocol 文件传输协议 ,21号端口 上传下载文件 |
DNS(53) domain name system 用于域名解析服务,将域名地址转为IP地址 |
ssh(22) secure shell 为远程登录会话和其他网络服务提供安全性的协议 |
|
Telnet(23) 远程登录协议,用户可以用自己的身份远程连接到计算机上,该端口可以提供一种基于DOS模式下的通信服务 |
SNMP(161) simple network management protocol 简单网络管理协议,是用来管理网络设置的 |
SMTP(25) simple mail transfer protocol 简单邮件传送协议,发送邮件(免费邮件服务中就是邮件服务端口) |
TFTP(69) trivial file transfer protocol 简单文件传输协议 |
POP3(110) post office protocol 与SMTP协议对应,用于接收邮件 |
NTP(123) network time protocol 网络时间协议,用来同步网络中各个计算机的时间协议 |
HTTP(80) hyper text transfer protocol 从Web服务器传输超文本到本地浏览器的传送协议 |
定义:
TCP是面向连接的、可靠的、传输层通信协议;
保证有效传输:
连接管理、校验和、序列号/确认应答、超时重传、流量控制(滑动窗口)、拥塞控制;
TCP可靠性体现在:有状态、可控制;
表现方面 | TCP可靠性 |
---|---|
有状态 | 指TCP会确认发送了哪些报文、对方接收了哪些报文,哪些没有收到 确保数据包按序到达,不允许有差错 |
可控制 | 如果出现丢包或网络状态不佳,则会跳转自己的行为,减少发送的速度或重发 |
TCP协议的三次握手;
最开始的时候,客户端和服务端的状态都是closed状态,客户端主动打开,服务器端被动打开,状态变成listen态;
客户端打开,向服务端发送连接请求报文段,标志位FIN=1,序列号seg =x,状态变成syn_sent;
服务端接收到客户端发送的连接请求,状态变成syn_rcvd,并发送确认连接请求,标志位FIN=1 ACK=1 seg = y ack = x+1;
客户端接收到服务端发送的确认连接请求之后,状态变成established,并发送确认连接请求,标志位ACK = 1 seq = x+1 ack=y+1
服务端接收到客户端发送的连接确认请求之后,状态变成established。
定义:
TCP校验和(CheckSum)是一个端到端的校验和,由发送端计算,然后由接收端验证;
目的:
为了发现TCP首部和数据在发送端到接收端之间发生的任何改变,如果接收方检测到校验和有误差,则TCP段会被直接丢弃;
TCP校验和的计算
TCP在计算校验和的时候,会在TCP首部加上一个12字节的伪首部;
TCP校验和的计算涉及:TCP伪首部、TCP头部、TCP数据;
扩展
TCP校验和覆盖:TCP伪首部、TCP首部和TCP数据,而IP首部中的校验和只覆盖IP的首部,不覆盖IP数据报中的任何数据;
TCP的校验和是必须的,UDP的校验和是可选的;
TCP和UDP计算校验和时,都要加上一个12字节的伪首部;
伪首部
定义——数据来自于IP数据报头,目的是为了TCP检查数据是否已经正确到达目的地,单纯为了校验,共12字节;
伪首部内容——源地址、目的地址、传输层协议号、TCP报文长度;
struct
{
unsigned long saddr;//源地址
unsigned long daddr;//目的地址
char mbz;//保留字节,强制置空
char ptcl;// 传输层协议号,协议类型
unsigned short tcpl;//TCP报文长度(报头+数据)
}psd_header;
发送方:
1 将TCP报头中的校验和字段 置为0
2 将TCP伪首部、TCP首部、TCP数据划分成16位的一个个16进制数
3 将这些数逐个相加,记得溢出的部分加到最低位上,循环加法
4 最后将结果取反求和,就可以得到校验和,并放入校验和位
接收方:
1 接收方按照发送放的方式将TCP伪首部、TCP首部、TCP数据部分划分成16位的一个个16进制数相加求得结果,
2 求得结果与校验和相加,如果全是1 则正确
序列号
TCP报文中的32位序列号,用来表示该方向上传输数据的序号;
确认应答
确认应答就是ACK应答,在TCP报文中32位确认号,表示收端想接收的下一个数据的序列号;
滑动窗口
在往返时间较长的情况下也能控制网络性能的下降;
确认应答不再是以每个分段进行确认,而是以更大的单位进行确认,这样转发时间会被大幅度的缩短。
采用窗口控制之后,对于某些确认应答丢失了也不需要重发;(即接收端接收数据,但是ACK报文没有到达发送端)
因为当窗口在一定程度上较大时,即使有少部分的确认应答丢失也不会进行数据重发,可以通过下一个确认应答进行确认;
慢开始
情况 | 具体执行 |
---|---|
cwnd < ssthresh | 阻塞窗口增加采用慢开始算法 |
cwnd > ssthresh | 拥塞窗口数量改变 采用拥塞避免算法 |
cwnd = ssthresh | 拥塞窗口数量改变 采用慢开始与拥塞避免算法 都可以 |
拥塞避免算法
快重传
出现原因:
为了避免由于报文段丢失产生的超时,错误开启拥塞避免算法导致网络传输速率低的问题,提出快重传;
思想:
让发送方尽快得知发生了个别报文段丢失的情况;
规定:
接收方不要等待自己发送数据时捎带确认信息,而是立即发送确认信息;
只要发送方收到三个连续的重复确认报文段X,就知道接收方确认没有收到报文段X+1,立即进行快重传;
扩展:
为什么采用接收方发送信息捎带确认信息?
确认信息数据很少,但TCP首部和IP首部占40个字节,效率低下;
解决方法就是 接收端发送信息的时候捎带这个确认信息;
快恢复
具体操作:
根据当前网络情况重新设置ssthresh门限值,调整为cwnd的一半,cwnd设置为原来的一半,此时ssthresh和cwnd一样,启动拥塞避免算法;
项目 | 说明 |
---|---|
作用 | 在某些实现中,用来防止在两个TCP之间的连接出现长时期的空闲 |
场景 | 假设客户端打开了到服务端的连接,传送一些数据之后就静默了(可能出现故障),该情况下,这个连接永远处于打开状态 |
处理 | 使用保活计数器,服务器每收到客户端数据,保活计数器复位; 设置阈值是2小时; 服务器两小时没有收到客户端的信息,发送探测文段; 如果发送10个探测文段(每个间隔75秒),还没有响应,就认为客户端发生故障,终止该连接; |
重传计时器
坚持计时器
保活计时器
时间等待计时器
TCP数据被封装在一个IP数据报中;
TCP可以表述为一个没有选择确认或否认的滑动窗口协议;
缺少选择确认 = TCP首部中的确认号表示发方已成功收到字节,但还不包含确认号所指的字节(即ack = 1024字节,表示收到了1-1023字节,不包含1024字节);
无法对数据流中选定的部分进行确认;
示例:
①收端并不能确认下一报文段:如果1-1024字节已成功接收,下一报文段中包含序号从2049-3072的字节,收端并不能确认下一报文段,所能做的就是发回一个确认序号为1024的ACK;
②无法对一个报文段进行否认:如果收到包含1024-2048字节的报文段,它的检验和错误,TCP接收端也只能发回一个ack = 1025的ACK;
字段 | 含义 |
---|---|
端口号 | 每个TCP段都包含源端和目的端的端口号,用于找寻发端和接收端应用进程 |
32位序号 | 就是TCP三次握手、四次挥手的seq,32位,无符号;字节流的字节计数器 |
32位确认号 | 确认号包含发送确认的一端所期望收到的下一个序号; 确认号应当是上次已经成功收到数据字节序号加1; 只有ACK标志位 = 1 时,该字段才有效; TCP全双工通信,数据在两个方向上都可以独立地进行传输,因此需要保证连接的每一端在该方向上的传输数据序号; |
4位首部长度 | 首部长度给出首部中的32bit字节数目;首部长度是可变的,通过该4位数据确定首部位数;没有可选字段则正常长度是20字节,最大长度是60字节(15*32/8 = 60) |
6个 标志比特位 | URG 紧急指针 ACK 确认序列号 PSH 接收方应该尽快将这个报文段交给应用层 RST 重建连接 SYN 同步序号用来发送一个连接 FIN 发端完成发送任务 |
2字节窗口大小 | 窗口值作为接收方让发送方设置其发送窗口的依据 |
2字节校验和 | 通过TCP伪首部、TCP首部、TCP数据部分计算而来,由发端计算和存储,由收端校验 |
16位紧急指针 | 当URG = 1才有效;是一个正偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号 |
TCP选项 | 最常见的可选字段是最长报文大小,又称为MSS(Maximum Segment Size)。 每个连接方通常都在通信的第一个报文段SYN标识的那个段指明 |
ARQ,自动重传请求(Automatic Repeat-reQuest),该协议是对滑动窗口很好的实现。
ARP协议包括:停等ARQ协议、连续ARQ协议(回退N帧ARQ协议、选择性重传ARQ协议)
ARP协议的特点:发送窗口的大小 <= 窗口总数
停等ARQ协议
连续ARQ协议
回退N帧ARQ协议(Go-Back-N)
选择性重传ARQ协议(Selective Repeat)
原理:
发送端连续发送数据包,且对每个数据包都设有单独的计时器;
当在一定时间内没有收到某个数据包的ACK时,发送端只重新发某个数据包即可;
客户端连续不断的向服务端发送数据包时,服务端接收的数据会出现两个数据包粘在一起的情况,这就是TCP协议中的粘包现象。
粘包产生
要发送的数据小于TCP发送缓冲的大小,TCP将多次写入缓冲区的数据一次性发出,产生粘包现象;
接收数据段的应用层没有及时读取接收缓冲去中的数据,发生粘包;
产生粘包的内在原因
TCP是面向字节流传输的,应用层和传输层之间的数据交换是大小不等的数据块,TCP协议会将数据块看成一串无结构的字节流,没有边界;
TCP首部中没有表示TCP数据报的长度的字段;
导致TCP粘包现象发生的原因可能出现在:TCP发送方 或 TCP接收方
发送方:
TCP协议传输数据的客户端与服务端保持长连接的状态,双方在不断开的情况下可以一直传输数据;
TCP需要尽可能高效和可靠交付,在数据包过小的时候,默认采用Nagle算法,以合并相连的小数据包,再一次性发送,以提升网络传输速率;
合并小数据包的过程是在发送缓冲区中进行的,也就是数据发送前就是粘包状态;
接收方不知道发送方进行了数据合并,并且数据包的合并在TCP协议中没有分界线,导致接收方无法还原本来的数据包。
接收方:
TCP是基于流的;
网络传输数据的速度可能会快过接收方处理数据的速度,导致接收方在读取缓冲区时,缓冲区有多个数据包;
从网络模型的下方传递至传输层,传输层TCP协议将数据放在缓冲区中,之后应用层主动来获取;
程序在调用读数据函数不能及时把缓冲区的数据拿出来,而下一个数据又进入到缓冲区中,此时读到的数据就是一个粘包;
拆包产生
要发送的数据大于TCP发送缓冲区的大小,将会产生拆包;
待发送数据大于MSS(最大报文长度),TCP在传输前进行拆包;
关键
如何给每个数据包添加边界信息;
解决方式
数据包长度。
发送端给每个包添加包首部,至少应该包含数据包的长度;接收端根据数据包长度得知数据包实际长度;
固定数据包长度。
发送端将每个数据包封装为固定长度(不够使用0补充);接收端每次从缓冲区读取固定长度的数据自然就将数据包拆分出来;
特殊符号。
发送端在数据包之间设置边界;接收端通过这个边界将不同的包拆分开来。
识别TCP连接 需要用一个四元组来唯一标识:local ip,local port ,remote ip ,remote port 。
两个角度:client和server 、 连接限制角度;
client和server
client
发起TCP连接请求,除非绑定端口,其余情况系统会选取一个闲置的本地端口,该端口是独占的,不和其他TCP连接共享;
tcp端口的数据类型是unsigned short(无符号整型,16位二进制),最大只有65536,端口0有特殊含义,只能使用65535;
server
固定在某个本地端口上监听,等待client的连接请求。
(即使server有多个ip,本地监听端口也是独占的)
server端tcp连接标识只有remote ip和remote port 可变;
因此最大连接数 = 客户端ip数 × 客户端port数 ,ip地址是32位;
最大TCP连接数 = 232 × 216
连接限制
可用端口数量、文件描述符数量、线程、内存、CPU。
限制因素 | 说明 |
---|---|
可用端口号限制 | 占满会报 不能分配所需请求地址 端口号16位,共65535个,可建立65535个连接 端口分为知名端口(0-1023)、注册端口(1024-49511)、动态/私有端口(49512-65535) 端口数可以修改,在vim/etc/sysctl.conf中修改 |
文件描述符限制 | 占满会报打开文件太多 每创建一个连接,操作系统就会分配一个文件描述符,受三方面限制。 Linux系统下查看 系统级:当前系统可打开的最大数量 = 通过cat /proc/sys/fs/file-max查看 用户级:指定用户可打开的最大数量,通过cat /etc/security/limits.conf查看 进程级:单个进程可打开的最大数量,通过cat /proc/sys/fs/nr_open查看 可修改单个进程最大文件描述符限制 每个socket就是一个文件描述符 |
线程 | 当服务器连接数达到1万且每个连接都需要消耗一个线程资源时,操作系统会不停地忙于进行线程的切换,最终导致系统崩溃; 传统的多线程并发模型(一个TCP连接需要创建一个线程) I/O多路复用:一个线程可以管理多个TCP连接的资源 |
内存 | TCP连接过多会出现内存溢出 原因:每一个TCP连接本身以及它的缓冲区 都需要占用一定的内存,内存占满会报错 |
CPU限制 | 每个TCP连接请求都会占用CPU资源,连接过多,电脑会卡死 |
TIME_WAIT状态
TIME_WAIT状态会的产生问题
浪费服务器资源:
在高并发短连接的TCP服务器上,当服务器处理完请求后主动请求关闭连接,这样服务器上会有大量的连接处于TIME_WAIT状态;
服务器维护每一个连接需要一个socket,也就是每个连接会占用一个文件描述符,而文件描述符的使用是有上限的,如果持续高并发,会导致一些连接失败。
不能及时重启:
假设服务器进程挂掉退出了,由于是服务器主动关闭连接,因此会有TIME_WAIT状态存在,也就意味着服务器进程想立即重启,但是起不来,因为端口(可能是80)还被之前处于TIME_WAIT的连接占用着,如果TIME_WAIT状态维持60秒,60秒服务器不能重启。
避免方式
设置套接字socket选项为SO_REUSEADDER = so_reuseaddr,表示如果端口繁忙,占用该端口TCP连接处于TIME_WAIT状态,并且套接字选项为SO_REUSEADDR,则该端口可被重用;
如果端口处于其他状态,依然返回端口被占用。
解决方式有两种:服务器设置SO_REUSEADDR套接字选项来通知内核;使用长连接减少TCP的连接与断开;
UDP具有无连接、不可靠、面向数据报的特点;
特点 | 说明 |
---|---|
无连接 | 知道对端IP和端口号就可以直接传输 |
不可靠 | 没有确认机制、重传机制 |
面向数据报 | 发送必须发送全部数据报内容,接收同样也是,要么读整个,要么不读 |
字段 | 说明 |
---|---|
报头 | UDP的报头是固定长度8字节,TCP的报头的可变长度,一般情况是20字节 |
端口号 | 16位的源/目的端口号,表示数据从哪里来,以及向哪里发送 |
UDP长度 | 16位,表示这个数据报(首部 + 数据)的最大长度,可以计算出该UDP报文的结尾在哪里 |
校验和 | 对整个UDP数据报进行校验,在UDP协议下,如果校验和出错,数据报直接被丢弃 |
UDP是无连接协议,具有资源消耗小,处理速度快的优点;在传输层无法保证数据的可靠传输,只能通过应用层来实现。
UDP实现可靠传输的方式:
使用UDP进行可靠数据传输的协议介绍:
RUDP
RTP
UDT