传输层
概述
传输层使用网络层的服务,为应用层提供通信服务
只有主机才有的层次
功能:
- 传输层提供进程和进程之间的逻辑通信
- 复用和分用
复用:应用层所有的应用进程都可以通过传输层再传输到网络层
分用:传输层从网络层收到数据后交付指明的应用进程
现有设备 A 和 B,都分别运行一个网页,一个 QQ,这两种程序的协议不同,设备 A 的两个进程都发送信息给设备 B。设备 A 的传输层根据协议的不同,对两组信息分别添加标识符,然后将两组信息打包传递给网络层发出去,这是复用;设备 B 的传输层从网络层接收到打包来的数据后,根据协议识别标识符,把给 QQ 的信息传送给 QQ,给网页的信息传送给网页,这是分用
- 对收到的报文进行差错检测
- 两种协议
TCP:面向连接的传输控制协议
可靠,面向连接,时延大,适用于大文件
UDP:无连接的用户数据报协议
不可靠,无连接,时延小,适用于小文件
寻址与端口
通过端口号标识主机中的应用进程
端口号长度为 16bit,能标识
套接字:唯一标识网络中的一个主机和它的一个进程
套接字 Socket = (主机 IP 地址,端口号)
UDP 协议
概述
UDP 只在 IP 数据报服务上增加少量功能,即复用分用和差错检测功能
特点:
- UDP 是无连接的,减少开销和发送数据之前的时延
- UDP 使用最大努力交付,即不保证可靠交付
- UDP 是面向报文的,适合一次性传输少量数据的网络应用
面向报文:完全接收应用层传输下来的完整报文,并封装传递到网络层,不会切割
- UDP 无拥塞控制,适合很多实时应用
例如对实时性要求较高的视频聊天等
- UDP 首部开销小
UDP 首部大小:8B
TCP 首部大小:20B
首部格式
源端口号:可有可无,不需要目标回话时可以不写(全 0)
UDP 长度:首部字段长度 + 数据字段长度
UDP 检验和:检测 UDP 数据报是否出错,错误则丢弃
UDP 校验
伪首部:只有在计算检验和时才出现,不向下传送也不向上递交
①:固定为 0
②:封装 UDP 报文的 IP 数据报首部协议字段是 17
UDP 长度:UDP 首部 8B + 数据部分长度(不包括伪首部)
在发送端:
- 填上伪首部
- 全 0 填充检验和字段
- 全 0 填充数据部分(UDP 数据报要看成许多 4B 的字串接起来)
- 伪首部 + 首部 + 数据部分采用二进制反码求和
- 把和求反码填入检验和字段
- 去掉伪首部,发送
在接收端:
- 填上伪首部
- 伪首部 + 首部 + 数据部分采用二进制反码求和
- 结果全为 1 则无差错,否则丢弃数据报/交给应用层附上出差错的警告
TCP 协议
特点
面向连接的传输层协议
传输数据前先接通连接,建立连接后传输数据,传输结束销毁连接
每条 TCP 连接只有两个端点,处于应用程序之间(端口),即每条 TCP 连接时是端对端的(不是点对点)
TCP 连接是端对端连接是怎么回事呢?TCP 连接相信大家都很熟悉,但是 TCP 连接是端对端连接是怎么回事呢,下面就让博主带大家一起了解吧。
TCP 连接是端对端连接,其实就是 TCP 连接是端对端连接,不是点对点连接。大家可能会很惊讶 TCP 连接怎么会是端对端连接呢?但事实就是这样,博主也感到非常惊讶。
这就是关于 TCP 连接是端对端连接的事情了,大家有什么想法呢,欢迎在评论区告诉博主一起讨论哦!TCP 提供可靠交付的服务,无差错、不丢失、不重复、按序到达
TCP 提供全双工通信
设置发送缓存和接收缓存
发送缓存:准备发送的数据 & 已发送但尚未收到确认的数据
接收缓存:按序到达但尚未被接受应用程序读取的数据 & 不按序到达的数据
TCP 面向字节流
流:流入到进程或从进程流出的字节序列
TCP 把应用程序交下来的数据看成仅仅是一连串的无结构的字节流
TCP 报文段首部格式
序列号:在一个 TCP 连接中传送的字节流中的每一个字节都按顺序编号,本字段表示本报文段所发送数据的第一个字节的序列号
确认号:期望收到对方下一个报文段的第一个数据字节的序列号。
若确认号为 N,则证明到序号 N-1 为止的所有数据都已正确收到,期望下一个收到的报文段的序号为 N
例题:
主机甲与主机乙之间建立 TCP 连接,主机甲向乙发送了一个序号为 100 的报文段,包含 200 字节的有效载荷,主机乙正确接收到这个报文段后,发送给主机甲的确认号为(300)
分析:当主机乙收到从序号 100 开始的 200 字节的有效载荷,最后一个字节序号应当是 299,确认号需要 +1,即发送确认号 300 给主机甲
数据偏移(首部长度):TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远,以 4B 位单位,即 1 个数值是 4B
首部中可能存在其他选项,导致首部长度不明,因此通过数据偏移,计算 TCP 数据部分在整个 TCP 报文段中的起始位置
6 个控制位:
紧急位URG
:URG=1
时,标明此报文段中有紧急数据,是高优先级的数据,应尽快传送,不用在缓存里排队,配合紧急指针字段使用
确认位ACK
:ACK=1
时确认号有效,在连接建立后所有传送的报文段都必须把 ACK 置为 1
推送位PSH
:PSH=1
时,接收方尽快交付接收应用进程,不再等到缓存填满再向上交付
复位RST
:RST=1
时,表明 TCP 连接中出现严重差错,必须释放连接,然后再重新建立传输链接
同步位SYN
:SYN=1
时,表明是一个连接请求/接受报文
终止位FIN
:FIN=1
时, 表明此报文段发送方数据已发完,要求释放连接
窗口:指的是发送本报文段的一方的接收窗口,即现在允许对方发送的数据量
接收方向发送方发送的报文段中,利用窗口指明接收方可以容纳的数据量,用来限制发送方的发送缓存大小
16bit 位,表示最大为
大小 例:
接收方报文段的确认号设置为 701,窗口设置为 1000
则发送方发出的报文段的字节序列号应当为从 701 到 1700
检验和:检验首部 + 数据,检验时要加上 12B 大小的伪首部,第四个字段为 6
紧急指针:URG=1
时才有意义,指出本报文段中紧急数据的字节数
从 TCP 数据报部分开头到指明的字节数长度的数据,作为紧急数据
选项:最大报文段长度 MSS、窗口扩大、时间戳、选择确……
TCP 连接管理(三次握手与四次挥手)
建立方式:客户服务器方式(C/S),主动发起连接建立的应用进程是客户,被动等待连接建立的应用进程是服务器
连接建立的三个阶段(三次握手)
客户端发送连接请求报文段(SYN),无应用层数据
SYN=1,seq=x(随机)
设置同步位
SYN
为 1,表明这是一个连接请求报文seq
(序列号)生成一个随机值client_isn
,记为 x发送前客户端处于
CLOSED
状态;发送后处于SYN_SENT
,并等待服务端返回的 SYNACK服务端为该 TCP 连接分配缓存和变量,并向客户端返回确认报文段(SYNACK),允许连接,无应用层数据
SYN=1,ACK=1,seq=y(随机),ack=x+1
确认报文段,则同步位
SYN
设置为 1确认位
ACK
设置为 1,表明确认号有效seq
(序列号)生成一个随机值server_isn
,记为 y确认号
ack
根据连接请求报文段中的序列号,+1,表示期望收到的下一个字节序列号服务器应用程序创建监听套接字,从
CLOSED
状态转变为LISTEN
状态当处于
LISTEN
状态并接收到 SYN 后,转变为SYN_RCVD
状态,并返回 SYNACK客户端为该 TCP 连接分配缓存和变量,并向服务端返回确认报文段的确认(ACK),可以携带数据
SYN=0,ACK=1,seq=x+1,ack=y+1
开始正常传输数据,同步位
SYN
设置为 0确认位
ACK
设置为 1,表明确认号有效收到 SYNACK 前客户端处于
SYN_SENT
状态;收到后处于ESTABLISHED
状态,此时客户端可以接收和发送包含有效载荷数据的 TCP 报文服务端收到 ACK 后由
SYN_RCVD
状态转变为ESTABLISHED
状态,等待客户端的正常请求并返回相应资源
SYN 洪泛攻击:客户端(攻击者)向服务器发送大量连接请求报文,接收到服务器的确认报文段后不进行确认,此时 TCP 连接处于挂起状态(半连接状态,服务器分配了缓存和变量);服务器接收不到确认,会重复发送 ACK 给攻击者,浪费服务器资源;大量的连接请求报文和恶意攻击,导致无法完成每一个三次握手,消耗服务器内存和 CPU,可能导致服务器死机
如何解决?
SYN cookie,如同浏览器的 cookie,服务器在接收到连接请求报文时,利用报文内的源和目的 IP 地址、端口号以及服务器自有的特殊值,通过特殊的复杂函数生成一个 cookie,并附加在连接确认报文中作为server_isn
发送回去,此时没有为这个 TCP 连接分配资源,也不会记录这个 cookie
如果客户端正常返回确认报文段,服务器端通过确认报文段中的源和目的 IP 地址、端口号以及服务器自有的特殊值,再次计算 cookie。此时报文段中的确认号应当是 cookie+1
连接释放的四个阶段(四次握手)
参与一条 TCP 连接的两个进程中的任何一个进程都可以终止该连接,释放缓存和变量
客户端发送连接释放报文段(FIN),停止发送数据,主动关闭 TCP 连接
FIN=1,seq=u
设置终止位
FIN
为 1,表明此报文段发送方数据已发完,要求释放连接序列号根据上一个报文段确定取值
发送 FIN 后客户端处于
FIN_WAIT_1
状态服务端返回一个确认报文段(ACK),客户端—服务器端这个方向的连接释放,处于半关闭状态
ACK=1,seq=v,ack=u+1
服务端接收到 FIN 后由
ESTABLISHED
状态转变为CLOSE_WAIT
状态客户端收到 ACK 后处于
FIN_WAIT_2
状态,等待服务端主动发送的连接释放报文段服务端发完数据,发出连接释放报文段(FIN),主动关闭 TCP 连接
FIN=1,ACK=1,seq=w,ack=u+1
设置终止位
FIN
为 1,表明此报文段发送方数据已发完,要求释放连接ack=u+1:第二步服务端发送报文段后,客户端并没有回发报文段,所以第二步和第三步服务端发送的报文段的
ack
都设置为 u+1服务端发送 FIN,由
CLOSE_WAIT
状态转变为LAST_ACK
状态客户端回送一个确认报文段(ACK),再等到时间等待计数器设置的
2MSL
(最长报文段寿命)后,连接彻底关闭ACK=1,seq=u+1,ack=w+1
客户端收到 FIN 后,发送 ACK,在时间等待计数器设置的时间内处于
TIME_WAIT
状态,经过等待后正式关闭服务端接收到 ACK 后,由
LAST_ACK
状态转变为CLOSED
状态当服务端没有接收到确认报文段时,会重发一个连接释放报文段,客户端在
2MSL
的时间中会接收到连接释放报文段后重发确认报文段
网络编程—C/S 模型
服务器:
1.socket()
,创建 socket,获得文件描述符
2.bind()
,绑定 socket 到服务器(本地 IP)对外暴露的端口
3.listen()
,对 socket 设置定长的监听队列,开始监听
4.accept()
,从监听队列中选取一个远端 socket(IP 和端口),建立连接
5.fork()
,分配逻辑处理单元,处理客户请求,监听 socket 继续监听
6.recv()
,逻辑处理单元接收客户端请求
7.send()
,发送客户端请求的数据
8.recv()
,接收客户端关闭通知,当业务处理完毕,调用close()
关闭服务器—> 客户端连接(TCP 四次挥手)
客户端:
1.socket()
,创建 socket,获得文件描述符
2.connect()
,由 socket 连接到服务器(IP 地址)的特定端口,双方进行 TCP 三次握手(及 HTTPS 的 TLS/SSL 四次握手)
3.send()
,通过 socket 向服务器发送请求
4.recv()
,接收服务器数据
5.close()
,关闭客户端—> 服务器连接(TCP 四次挥手)
TCP 可靠传输
网络层提供尽最大努力交付,不可靠传输;传输层使用 TCP 实现可靠传输(UDP 不可靠,需要应用层实现可靠传输)
可靠传输:保证接收方进程从缓存区读出的字节流与发送方发出的字节流是完全一样的
- 校验:增加伪首部检验
- 序号:一个字节占一个序号
序号字段:一个报文段的第一个字节的序号 - 确认:接收方发送确认报文段,指导发送方接下来应该发送的数据
例:
发送方 TCP 缓存:有十个字节,序号从 1 到 10,先发送序号从 1 到 3 的字节;发送后缓存中不删除 1 到 3 号字节
接收方 TCP 缓存:接收从 1 到 3 号的字节,存入缓存
接收方向发送方发送确认报文段,首部中确认号为 4,表示希望发送方接下来发送以以序号 4 的字节开头的数据
发送方接收到确认报文段,确认 1 到 3 号正常接收,删除缓存中的 1 到 3 号;并根据要求发送 4 到 6 号,和 7 到 8 号
接收方未接收到 4 号开头的数据,但是接收到了 7 号开头的数据;此时默认使用累计确认,返回确认报文段,确认号仍然为 4,指导接收方重传 4 开头的数据
- 重传:发送方在规定时间(重传时间)内没有收到确认就重传已发送的报文段(超时重传)
重传时间:自适应算法,计算 RTTs(加权平均往返时间)
根据每次发送报文段和接收确认报文段的往返时间,加权计算,动态改变重传时间
TCP 流量控制
流量控制:让发送方慢点,让接收方来得及接收
TCP 利用滑动窗口机制实现流量控制
在通信过程中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小,即接收窗口 rwnd(接收方设置确认报文段的窗口字段来将 rwnd 通知给发送方),发送方的发送窗口取接收窗口 rwnd 和拥塞口 cwnd 的最小值
接收方可以设置窗口为 0,此时发送方不能发送数据,接收方可以处理数据;接收方处理后再发送一个报文段,重新设置窗口大小,发送方根据窗口大小继续发送数据
A 向 B 发送数据,连接建立时,B 告诉 A:『 我的 rwnd=400 (字节)』,设每一个报文段 100B,报文段序号初始值为 1
接收方设置窗口为 0,重新发送报文段设置窗口时,报文段可能丢失,导致发送方窗口一直为 0,接收方一直等着发送方的报文,形成『死锁』
TCP 为每一个连接设有一个持续计时器,只要 TCP 连接的一方收到对方的零窗口通知,就启动持续计时器
若持续计时器设置的时间到期,就发送一个零窗口探测报文段。接收方收到探测报文段时给出现在的窗口值
若窗口仍然是 0,那么发送方就重新设置持续计时器
TCP 拥塞控制
拥塞条件:对资源需求的总和 > 可用资源
拥塞控制:防止过多的数据注入到网络中
假定:
- 数据单方向传送,而另一个方向只传送确认
- 接收方总是有足够大的缓存空间,因而发送窗口大小取决于拥塞程度
发送窗口 = Min { 接收窗口 rwnd,拥塞窗口 cwnd }
接收窗口:接收方根据接受缓存设置的值,并告知给发送方,反映接收方容量
拥塞窗口:发送方根据自己估算的网络拥塞程度而设置的窗口值,反映网络当前容量
慢开始和拥塞避免
一个传输轮次:
发送了一批报文段并收到它们的确认的时间
一个往返时延 RTT
开始发送一批拥塞窗口内的报文段到开始发送下一批拥塞窗口内的报文段的时间