tcp/udp协议概述
传输层协议基本概念
传输层协议建立在网络层和会话层之间,为应用层实体提供端到端的通信功能,确保数据包的顺序传送及数据的完整性。它利用网络层提供的服务,并通过传输层地址(端口号)提供给高层用户传输数据的通信端口,使得应用进程之间能够进行可靠的、透明的数据传输,
这里我们需要给大家介绍一下常见的网络模型,最先是OSI七层网络模型,但是后来变为TCP/IC四层模型。
网络模型
OSI七层网络模型:
每一层都专注做一件事情,并且每一层都需要使用下一层提供的功能比如传输层需要使用网络层提供的路由和寻址功能,这样传输层才知道把数据传输到哪里去。OSI 的七层体系结构概念清楚,理论也很完整,但是它比较复杂而且不实用,而且有些功能在多个层中重复出现。
TCP/IP四层网络模型:
而我们的五层TCP/IP网络模型是将网络接口层换为
物理层和数据链路层
,
TCP/UDP在网络模型的位置
由图可知,我们的TCP/UDP位于传输层的位置
传输层: 传输层是TCP/IP协议五层模型中的第四层。它提供了应用程序间的通信,它负责数据能够从发送端传输到接收端。其功能包括:一、格式化信息流;二、提供可靠传输。为实现后者,传输层协议规定接收端必须发回确认,并且假如分组丢失,必须重新发送。
再谈端口号: 在网络知识扫盲博客中谈到端口号标识了一个主机上进行通信的不同应用程序。在TCP/IP协议中, 用"源IP", “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过 netstat -n查看,协议号指的是那个使用协议)。
一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定。
端口号范围划分:
0 - 1023: 知名端口号,HTTP、FTP、 SSH等这些广为使用的应用层协议他们的端口号都是固定的,自己写的程序中,不能随意绑定知名端口号。
1024 - 65535:操作系统动态分配的端口号。 客户端程序的端口号,就是由操作系统从这个范围分配的。
常见的知名端口号:
ssh服务器:22端口
ftp服务器:21端口
http服务器:80端口
telnet服务器:23端口
https服务器:443端口
MYSQL服务器:3306端口
在Linux操作系统中使用命令cat /etc/services可以看到所有的知名端口。
netstat工具: 用来查看网络状态。
n 拒绝显示别名,能显示数字的全部转化成数字
l 仅列出有在Listen (监听)的服务状态
p 显示正在使用Socket的程序识别码和程序名称
t (tcp)仅显示tcp相关选项
u u (udp)仅显示udp相关选项
a (all)显示所有选项,默认不显示LISTEN相关
pidof [进程名]: 可以根据进程名直接查看服务器的进程id。例如:pidof sshd。
TCP/UDP的区别
连接方式
TCP:是面向连接的协议,在数据传输前,通信双方需要通过三次握手建立连接,数据传输完成后,还需通过四次挥手释放连接。例如,当你访问网页时,浏览器和服务器之间会先建立TCP连接,之后才开始传输网页数据。
UDP:是无连接的协议,发送数据之前不需要建立连接,发送后也无需释放连接。发送方只需将数据封装成数据报发送出去,接收方直接接收数据报。像在网络上观看视频或者听音乐时,大多使用UDP传输协议。传输可靠性
TCP:提供可靠的传输服务,它通过多种机制来确保数据的正确传输。包括面向字节流和缓存机制,将应用数据分割成适合发送的数据块;超时重发和确认机制,发送数据段后启动定时器,若未及时收到确认则重发;检验和机制,检测数据在传输过程中的变化;字节编号机制,对字节进行编号,接收方按顺序交给应用层;自动丢弃重复机制,丢弃重复的数据。这些机制保证了数据的完整、无损且按顺序到达。
UDP:提供不可靠的传输服务,不保证数据的可靠交付,不确认报文是否到达,不对报文排序,也没有超时重发等机制。应用程序需要自己承担可靠性方面的工作。比如,在实时视频流中,如果个别数据包丢失,可能不会对整体观看体验造成太大影响,UDP不会为此进行重传。传输效率
TCP:由于要建立连接、进行确认、重传等操作,会产生一定的开销,传输效率相对较低,传输速度较慢。而且TCP不支持多播和广播,只能进行一对一的通信。
UDP:没有连接建立和维护的开销,也没有拥塞控制机制,当网络出现拥塞时不会降低源主机的发送速率,因此传输速度快,适用于对实时性要求高、允许少量数据丢失的应用场景,如实时音视频传输、在线游戏等。数据顺序
TCP:保证数据的顺序性,接收方会按照发送方发送数据的顺序将数据交付给应用层。即使数据在网络中可能会乱序到达,TCP也会在接收端进行排序。
UDP:不保证数据的顺序性,数据报可能会以乱序的方式到达接收方,接收方需要自己处理数据的顺序问题。首部开销
TCP:首部开销较大,一般为20个字节,包含了源端口、目的端口、序列号、确认号等多个字段,用于实现可靠传输和连接管理等功能。
UDP:首部开销较小,只有8个字节,仅包含源端口、目的端口、长度和检验和四个字段,主要用于标识发送端和接收端的端口号以及数据报的长度和校验。
- 应用场景
TCP:适用于对数据准确性、完整性要求较高,对实时性要求相对较低的应用,如文件传输(FTP)、电子邮件(SMTP)、网页浏览(HTTP)等。
UDP:适用于对实时性要求较高、对数据丢失不太敏感、传输经济性要求较高的应用,如视频直播、在线游戏、域名系统(DNS)查询、实时音视频通信等。
tcp
头部格式
源端⼝号和⽬的端⼝号:
⽤于多路复⽤/分解来⾃或送到上层应⽤的数据。告诉主机报⽂段来⾃哪⾥,传给哪个上层协议或应⽤程序。
序列号:
该报⽂段⾸字节的字节流编号,⽤来解决⽹络包乱序问题。确认应答号:对发送来的 TCP 报⽂段的响应,值是收到的 TCP 报⽂段的序号值加1,⽤来解决不丢包的问题。序列号和确认应答号都⽤于实现可靠数据传输。
⾸部⻓度:
标识 TCP 头部有多少字节,最⻓ 60。
窗⼝⼤⼩:
接收窗⼝,告诉对⽅本端TCP缓冲区还有多少空间可以接收数据,⽤来做流量控制。
标志字段:
ACK:⽤于指示确认应答号值是否有效,置1表示包含⼀个对已成功接收报⽂段的确认;
RST:⽤于重置⼀个已经混乱的连接,或拒绝⼀个⽆效的数据段或者连接请求;
SYN:⽤于连接建⽴过程,请求建⽴⼀个连接;
FIN:⽤于断开连接,表示发送⽅没有数据要传输了。
检验和:
接收⽅使⽤检验和来检查该报⽂段(头部+数据)中是否出现差错(CRC算法),同 UDP。
列举TCP选项
TCP头部的最后⼀个选项字段(options)是可变⻓的可选信息。这部分最多包含40字节,因为TCP头部最⻓是60
字节(其中还包含前⾯讨论的20字节的固定部分)。
选项的第⼀个字段kind说明选项的类型,有的TCP选项没有后⾯两个字段,仅包含1字节的kind字段。
第⼆个字段length(如果有的话)指定该选项的总⻓度。该⻓度包括kind字段和length字段占据的2字节。
第三个字段info(如果有的话)是选项的具体信息。
常见的TCP选项(7种)
1、kind=0,选项表结束(EOP)选项。
⼀个报⽂段仅⽤⼀次。放在末尾⽤于填充,⽤途是说明:⾸部已经没有更多的消息,应⽤数据在下⼀个32位字开始
处。
2、kind=1,空操作(NOP)选项。
没有特殊含义,⼀般⽤于将TCP选项的总⻓度填充为4字节的整数倍。
3、kind=2,最⼤报⽂段⻓度(MSS)选项。
TCP连接初始化时,通信双⽅使⽤该选项来协商最⼤报⽂段⻓度。TCP模块通常将MSS设置为(MTU-40)字节(减
掉的这40字节包括20字节的TCP头部和20字节的IP头部)。
这样携带TCP报⽂段的IP数据报的⻓度就不会超过MTU(假设TCP头部和IP头部都不包含选项字段,并且这也是⼀
般情况),从⽽避免本机发⽣IP分⽚。对以太⽹⽽⾔,MSS值是1460(1500-40)字节。
4、kind=3,窗⼝扩⼤因⼦选项。
TCP连接初始化时,通信双⽅使⽤该选项来协商接收窗⼝的扩⼤因⼦。在TCP的头部中,接收窗⼝⼤⼩是⽤16位表
示的,故最⼤为65535字节,但实际上TCP模块允许的接收窗⼝⼤⼩远不⽌这个数(为了提⾼TCP通信的吞吐
量)。窗⼝扩⼤因⼦解决了这个问题。
假设 TCP 头部中的接收通告窗⼝⼤⼩是 N,窗⼝扩⼤因⼦(移位数)是 M,那么 TCP 报⽂段的实际接收通告窗⼝
⼤⼩是 N*2M,或者说 N 左移 M 位。注意,M的取值范围是 0~14。
和 MSS 选项⼀样,窗⼝扩⼤因⼦选项只能出现在同步报⽂段中,否则将被忽略。但同步报⽂段本身不执⾏窗⼝扩
⼤操作,即同步报⽂段头部的接收窗⼝⼤⼩就是该 TCP 报⽂段的实际接收窗⼝⼤⼩。当连接建⽴好之后,每个数据
传输⽅向的窗⼝扩⼤因⼦就固定不变了。
5、kind=4,选择性确认(Selective Acknowledgment,SACK)选项。
TCP 通信时,如果某个 TCP 报⽂段丢失,则 TCP 会重传最后被确认的 TCP 报⽂段后续的所有报⽂段,这样原先已
经正确传输的 TCP 报⽂段也可能重复发送,从⽽降低了 TCP 性能。
SACK 技术使 TCP 只重新发送丢失的 TCP 报⽂段,⽽不⽤发送所有未被确认的 TCP 报⽂段。选择性确认选项⽤在
连接初始化时,表示是否⽀持 SACK 技术。
6、kind=5,SACK实际⼯作的选项。
该选项的参数告诉发送⽅本端已经收到并缓存的不连续的数据块,从⽽让发送端可以据此检查并重发丢失的数据
块。
每个块边沿(edge of block)参数包含⼀个4字节的序号。其中块左边沿表示不连续块的第⼀个数据的序号,⽽块
右边沿则表示不连续块的最后⼀个数据的序号的下⼀个序号。这样⼀对参数(块左边沿和块右边沿)之间的数据是
没有收到的。因为⼀个块信息占⽤8字节,所以 TCP 头部选项中实际上最多可以包含4个这样的不连续数据块(考
虑选项类型和⻓度占⽤的2字节)。
7、kind=8,时间戳选项。
该选项提供了较为准确的计算通信双⽅之间的回路时间(Round Trip Time,RTT)的⽅法,为TCP流量控制提供信
息。
可靠传输机制
三次握手四次挥手
TCP 是⾯向连接的协议,所以使⽤ TCP 前必须先建⽴连接,⽽建⽴连接是通过三次握⼿来进⾏的
1、第⼀次握⼿:SYN报⽂:
客户端随机初始化序列号
client_isn ,放进TCP⾸部序列号段,然后把SYN置1。把SYN报⽂发送给服务端,表示
发起连接,之后客户端处于
SYN-SENT 状态。
2、第⼆次握⼿:SYN+ACK报⽂:
服务端收到客户端的SYN报⽂之后,会把⾃⼰随机初始化的序号
号」填⼊
server_isn 放进TCP⾸部序列号段,「确认应答
client_isn + 1 ,把SYN和ACK标志位置为1。把SYN+ACK报⽂发送给客户端,然后进⼊
SYN-RCVD 状
态,表示服务器接受了客户端的请求,并希望建⽴连接。
3、第三次握⼿:ACK报⽂:
客户端收到服务端报⽂后,还要向服务端回应最后⼀个应答报⽂。⾸先该应答报⽂ TCP ⾸部 ACK 标志位置为 1 ,
其次「确认应答号」字段填⼊
server_isn + 1 ,最后把报⽂发送给服务端,这次报⽂可以携带客户到服务器的
数据,之后客户端处于
ESTABLISHED 状态, 表示客户端已经准备好与服务器进⾏数据传输。
服务器收到客户端的应答报⽂后,也进⼊
ESTABLISHED 状态。
此时,TCP 连接已经建⽴起来,通信双⽅可以开始进⾏数据传输
- 第三次握⼿是可以携带数据的,但是前两次握⼿是不可以携带数据的。
为什么需要三次握手
三次握⼿才能保证双⽅具有接收和发送的能⼒
- 三次握⼿才可以阻⽌重复历史连接的初始化(主因)
- 三次握⼿才可以同步双⽅的初始序列号
- 三次握⼿才可以避免资源浪费
解释:
- 1.阻⽌重复历史连接的初始化(主因)
-
- 当因为⽹络阻塞原因,客户端向服务器发送了两次SYN报⽂
- 2.旧的SYN报⽂先到达服务端,服务端回⼀个ACK+SYN报⽂
- 3.客户端收到后可以根据⾃身的上下⽂,判断这是⼀个历史连接(序列号过期或超时),那么客户端就会发送 RST 报⽂给服务端,表示中⽌这⼀次连接。
-
- 服务器收到RST报⽂,会释放连接
-
- 新的SYN报⽂抵达之后,客户端和服务器之间进⾏正常的三次握⼿
-
如果只是两次握⼿,服务端在收到SYN报⽂之后,就进⼊到
ESTABLISHED 状态, 服务器端并不知道这次是历史连
接,直接与客户端建⽴连接并向客户端发送数据(资源浪费),但是客户端会判定这次连接是历史连接,从⽽发送RST报⽂来断开连接。
所以要想让服务器发送数据前,阻⽌掉历史连接,就需要三次握⼿。
- 2、同步双⽅的初始序列号
TCP 协议的通信双⽅, 都必须维护⼀个「序列号」, 序列号是可靠传输的⼀个关键因素。
1.接收端可以去除重复数据。
2.接收端可以按照序列号顺序接收。
3.标识发送的数据包,哪些已经被收到。
过程
- 客户端发送第⼀个报⽂,携带客户端初始序列号的SYN报⽂。
- 服务器发送第⼆个报⽂,携带服务器初始序列号的ACK + SYN的应答报⽂,表示收到客户端的SYN报⽂。
- 客户端发送第三个报⽂,携带服务器的ACK应答报⽂。
这样⼀来⼀回,才能确保双⽅的初始序列号能被可靠的同步。
两次握⼿只保证了⼀⽅的初始序列号能被对⽅成功接收,没办法保证双⽅的初始序列号都能被确认接收。四次握⼿
也能保证双⽅的初始化序号同步,但是可以省略成三次。
3、避免资源浪费。
- 只有两次握⼿时,如果客户端的SYN请求连接在⽹络中阻塞,客户端没有收到服务端的ACK报⽂,会重新发送
SYN。 - 由于没有第三次握⼿,服务器不清楚客户端是否收到了⾃⼰发送的建⽴连接的 ACK 确认信号,所以每收到⼀
个 SYN 就只能先主动建⽴⼀个连接, 建⽴多个冗余的⽆效链接,造成不必要的资源浪费。
所以通过TCP三次握⼿,能能防⽌历史连接的建⽴,能减少双⽅不必要的资源开销,能帮助双⽅同步初始化序列号
- 「两次握⼿」:⽆法防⽌历史连接的建⽴,会造成双⽅资源的浪费,也⽆法可靠的同步双⽅序列号;
- 「四次握⼿」:三次握⼿就已经理论上最少可靠连接建⽴,所以不需要使⽤更多的通信次数。
半连接状态
半连接队列(SYN队列)⽤于存放已经发送了 SYN(同步)包,但还未完成三次握⼿的连接:服务器第⼀次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双⽅还没有完全建⽴其连接,服务器会把此种状态下请求连接放在⼀个队列⾥,我们把这种队列称之为半连接队列。
全连接队列(Accept队列)⽤于存放已经完成三次握⼿,处于完全建⽴连接状态的连接。
SYN攻击
在 SYN 攻击中,攻击者发送⼤量伪造的 SYN 请求到⽬标服务器,但不完成后续的握⼿过程,从⽽让服务器⼀直等待确认,消耗服务器的资源(如半连接队列和系统资源),当半连接队列满了之后,后续再收到SYN报⽂就会丢弃,导致⽆法与客户端之间建⽴连接。
四次挥手
TCP 断开连接是通过四次挥⼿来进⾏的,四次挥⼿的过程如下图:
四次挥⼿的过程
在挥⼿之前,客户端和服务器都处于
ESTABLISHED 状态
- 第⼀次挥⼿:假设客户端打算关闭连接,发送⼀个TCP⾸部FIN被置1的
FIN_WAIT1 状态
FIN 报⽂给服务端, 此时客户端处于 - 第⼆次挥⼿:服务端收到以后,向客户端发送ACK应答报⽂,且把客户端的序列号值+1作为ACK报⽂的序列号
值,表明已经收到客户端的报⽂了,此时服务端处于
CLOSE_WAIT 状态 - 第三次挥⼿:等待服务端处理完数据后,向客户端发送FIN报⽂。此时服务端处于
LAST_ACK 的状态 - 第四次挥⼿:客户端接收到FIN报⽂后回⼀个ACK应答报⽂,之后客户端处于
TIME_WAIT 状态 - 服务器收到ACK报⽂后,进⼊
CLOSE 状态,服务器完成连接关闭。 - 客户端在经过 2MSL ⼀段时间后,⾃动进⼊
CLOSE 状态,客户端也完成连接的关闭。
为什么挥⼿需要四次
关闭连接时,客户端发送FIN报⽂,表示其不再发送数据,但还可以接收数据。
服务端收到FIN报⽂,可以直接发送SYN+ACK报⽂。其中ACK报⽂是⽤来应答的,SYN报⽂是⽤来同步的。但是关闭连接时,服务端可能还要数据需要处理和发送,所以先回⼀个ACK应答报⽂,等到其不再发送数据时,才发送FIN报⽂给客户端表示同意关闭连接。
从上⾯过程可知:服务端通常需要等待完成数据的发送和处理,所以服务端的ACK和FIN⼀般都会分开发送,从⽽⽐三次握⼿导致多了⼀次。
为什么需要 TIME_WAIT 状态
主动发起关闭连接的⼀⽅,才会有 TIME-WAIT 状态。
需要 TIME-WAIT 状态,主要是两个原因:
- 防⽌历史连接中的数据,被后⾯相同四元组的连接错误的接收;
如果⽹络出现拥塞或延迟,数据包可能会在⽹络中滞留⼀段时间,甚⾄超过了原始连接关闭的时间。如果没有 TIME_WAIT 状态,客户端直接进⼊到CLOSE状态,这些滞留的数据包可能会被传递给新连接,导致新连接的数据被旧连接的数据⼲扰。
经过 2MSL 这个时间,⾜以让两个⽅向上的数据包都被丢弃,使得原来连接的数据包在⽹络中都⾃然消失,再出现的数据包⼀定都是新建⽴连接所产⽣的。 - 保证「被动关闭连接」的⼀⽅能被正确的关闭,即保证最后的 ACK 能让被动关闭⽅接收,从⽽帮助其正常关闭
如果最后的⼀次ACK报⽂丢失(第四次挥⼿),客户端没有TIME_WAIT 状态,直接进⼊ClOSE,服务端⼀直在等待ACK状态,⼀直没有等到,就会重发FIN报⽂,⽽客户端已经进⼊到关闭状态,在收到服务端重传的 FIN 报⽂后,就会回 RST 报⽂,服务端收到这个 RST 并将其解释为⼀个错误, 为了防⽌这种情况出现,客户端必须等待⾜够⻓的时间,确保服务端能够收到 ACK,如果服务端没有收到 ACK,那么就会触发 TCP 重传机制,服务端会重新发送⼀个 FIN,这样⼀去⼀来刚好两个 MSL 的时间。
如果 TIME-WAIT 等待⾜够⻓的情况就会遇到两种情况:
- 服务端正常收到四次挥⼿的最后⼀个 ACK 报⽂,则服务端正常关闭连接。
- 服务端没有收到四次挥⼿的最后⼀个 ACK 报⽂时,则会重发 FIN 关闭连接报⽂并等待新的 ACK 报⽂。
为什么 TIME_WAIT 等待的时间是 2MSL
- MSL是 Maximum Segment Lifetime ,报⽂最⼤⽣存时间,它是任何报⽂在⽹络上存在的最⻓时间,超过这个时间报⽂将被丢弃。
- 等待MSL两倍:⽹络中可能存在发送⽅的数据包,当这些发送⽅的数据包被接收⽅处理后⼜会向对⽅发送响应,所以⼀来⼀回需要等待 2 倍的时间。
- 1 个 MSL 确保四次挥⼿中主动关闭⽅最后的 ACK 报⽂最终能达到对端;1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报⽂可以到达。
- 2MSL 的时间是从客户端接收到 FIN 后发送 ACK 开始计时的。如果在 TIME-WAIT 时间内,因为客户端的 ACK 没有传输到服务端,客户端⼜接收到了服务端重发的 FIN 报⽂,那么 2MSL 时间将重新计时。
TIME_WAIT 过多有什么危害?
过多的TIME-WAIT 状态主要的危害有两种:
- 内存资源占⽤;
- 对端⼝资源的占⽤,⼀个 TCP 连接⾄少消耗⼀个本地端⼝;
如果发起连接⼀⽅的
TIME_WAIT 状态过多,占满了所有端⼝资源,则会导致⽆法创建新连接。
####TCP重传机制
//to do
####滑动窗口
/todo
####流量控制
//todo
####拥塞控制
//todo
####快速恢复
UDP
####报文结构
⽬标端⼝和源端⼝:
主要是告诉 UDP 协议应该把报⽂发给哪个进程。
包⻓度:
该字段保存了 UDP ⾸部的⻓度跟数据的⻓度之和。
校验和:
校验和是为了提供可靠的 UDP ⾸部和数据⽽设计,接收⽅使⽤检验和来检查该报⽂段中是否出现差错。