网络原理之TCP_IP_1

本文深入探讨了TCP和UDP两大传输层协议。TCP是面向连接、可靠的协议,采用三次握手建立连接,通过确认应答、超时重传、滑动窗口等机制确保数据可靠性。而UDP则是无连接、不可靠的协议,适合于对实时性要求高的应用。两者在数据传输的安全性和效率上存在明显差异,适用于不同的应用场景。
摘要由CSDN通过智能技术生成

网络原理之TCP_UDP

本文主要讲述传输层的两大重要传输层协议TCP和UDP

img

UDP协议

UDP协议段格式

从图中可以看出UDP由首部字段和数据字段构成,数据字段是需要传输的数据.首部字段由源端口号,目的端口,UDP长度,检验和组成,每个字段的大小为2字节.

  • 源端口号: 发送数据报的应用进程的端口号.
  • 目的端口号:接受数据报的端口号.
  • UDP长度: UDP数据报的长度,最大为2字节
  • 校验和: 检测在传输过程中,数据是否被第三方篡改或者由于网络波动等原因受到破坏.但是UDP在检测到错误后,不会做错误校正,而是把损坏的消息段扔掉或者给应用程序提供警告信息.

伪首部作用:

伪首部不是真正的首部,只是在计算校验和时在UDP前面添加12字节的字段,是一个临时数据,所以它既不向上传输,也不向下传输.

UDP的校验方法:

  1. 发送方把校验和字段全部填充为0,并且在首部添加12字节的伪首部.
  2. 若UDP数据报的数据部分不是偶数个字节,则要在数据部分末尾增加一个全零字节(但此字节不发送).
  3. 按二进制反码计算出这些16位字的和,并将此和的二进制反码写入校验和字段
  4. 接收方把收到的UDP数据报加上伪首部(如果不为偶数个字节,那还需要补上全零字节)后,按二进制反码计算出这些16位字的和.
  5. 当无差错时其结果应全为1,否则表明有差错出现,接收方就应该丢弃这个UDP数据报.

检验过程中采用的是CRC算法(循环冗余校验),其优势为检错能力极强,且检测成本低.

但是校验和相等不一定数据是准确的.例如会遇见1 + 9 = 10和5+5 = 10的情况.

UDP协议特点

  1. 无连接

在传输数据时不需要源端和终端建立连接,只需要知道目的端口号和IP地址就可以发送,在发送端,其传输速度受到应用程序生成数据速度,传输带宽的限制,在接受端,UDP把每个消息段放在队列中,每次需要时从队列中读取.

  1. 不可靠传输

在发送端发出UDP报文后,即使在传输过程中受到破坏,也不会反馈任何信息.

  1. 面向数据报

UDP是面向报文的,对于应用程序下发的报文,在添加首部后直接下发给IP层,既不会拆分,也不会合并.

  1. 缓冲区

UDP发送的数据会交付给内核,然后由内核把数据传给网络层,所以没有发送缓存区,UDP具有接受缓冲区,由于数据传输具有"后发先至"的特点,所以并不能保证接受缓存区中的数据和发送顺序相同.

  1. 全双工

UDP的Socket即能读,又可以写.

  1. 不可靠

UDP协议是一个不可靠的协议,它对数据是否传输到目的端口不清楚.

应用场景

在网络质量情况不好的情况下,UDP协议数据包丢失会比较严重,应该避免使用.然而由于UDP的特性:它不属于连接线协议,因此具有资源消耗小,处理速度快的优点,所以通常音频,视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响,比如我们聊天用的QQ]就是使用的UDP协议.

TCP协议

TCP是有连接,可靠的,面向字节流,全双工的传输层通信协议.

TCP协议段格式

img

TCP虽然是面向字节流,但是其传输数据单元依然是报文,由图可以看出,TCP报文段由TCP首部和数据部分构成,TCP首部详细信息如图:

  • 源端口号和目的端口: 各占2个字节,表明报文段传输的源头和终点

  • 32位序号(Sequence number): 占4字节,TCP是面向字节流的,在编号时是按照字节来编写的,例如有一个TCP报文段,序号为1, 长度为1000,那么在数据部分的第一个数据序号为1, 最后一个就是1001.

    • TCP对每个字节数据都进行了编号,即为(序号)序列号:

  • 32位确认序号(Acknowledge number): 占4字节,如果当前报文是一个普通的报文,确认序号不生效,如果是应答报文,确认序号就表示应答的是哪一个普通报文,继续上面的例子,该TCP报文的应答报文就是1001,表明小于1001的数据已经收到了.

  • 4位首部长度: TCP首部的大小

  • 保留: 保留使用

  • 6位标志位

    • URG( 紧急 urgent) 当URG=1,表明紧急指针字段有效,该报文段有紧急数据,应尽快发送.
    • ACK(确认 acknowledgement) 仅当ACK=1时,确认号才有效,连接建立后,所有的报文段ACK都为1
    • PSH(推送 push) 接收方接收到PSH=1的报文段,提示接收端应用程序立刻从TCP缓冲区把数据读走
    • RST(复位 reset) RST=1时,表明TCP连接中出现严重差错,必须是否连接,再重连,我们把携带RST标识的称为复位报文段
    • SYN(同步 synchronization) 在建立连接时用来同步序号.当SYN=1,ACK=0,则表明是一个连接请求报文段.SYN=1,ACK=1则表示对方同意连接.我们把携带SYN标识的称为同步报文段
    • FIN(终止 finish ) 用来释放一个连接窗口.当FIN=1时,通知对方,本端要关闭了, 我们称携带FIN标识的为结束报文段
  • 窗口 表示发送方自己的接收窗口,窗口值用来告诉对方允许发送的数据量。

  • 16位校验和发送端填充,CRC校验.接收端校验不通过,则认为数据有问题.此处的检验和包含TCP首部和TCP数据.

  • 紧急指针 URG=1时,紧急指针指出本报文段中的紧急数据的字节数.

  • 选项 长度可变,最长可达40字节

TCP原理

TCP不同于UDP一个重要点是**“安全"和"可靠”**,即在保证数据传输安全的前提下,尽可能地提高传输效率.所以就出现很多机制来确保可靠性安全

确认应答机制

首先主机A和主机B建立连接,主机A发送TCP数据报(发送了1000个字节地数据,确认序号为1001,因为是应答报文,所以ACK = 1),当主机B接受到应答报文后,给主机A返回确认序号1001,表明小于1000地数据我已经收到了,主机A可以继续从1001发送数据.

于是就保证数据在接受端成功接受数据.

超时重传机制

在确认应答机制下,由于网络拥挤等原因导致长时间没有及时接受到ACK,此时并不是立即放弃,而是等待特定时间后重传数据

情况1: 业务数据丢失

主机A发送地数据报在传输过程中丢失,没有接受ACK,会在特定时间后重发.

情况2:ACK丢失

主机B发送的ACK丢失,导致主机A重复发送,那么就会多了许多重复数据报,这时候就可以利用序号去重.

连接管理机制

在分析三次握手,四次挥手的过程时,先了解重要字段TCP状态的意义:

重要字段:

  • seq (sequence number) 序号
  • ack (acknowledgement number) 确认号
  • 标志位:
    • SYN (synchronization) 同步
    • ACK (acknowledgement) 确认
    • FIN (finish) 终止

TCP状态:

  • LISTEN: 服务端打开Soket进行监听,正在监听其他地方的TCP端口的连接请求,此时该服务器端口是开放的,正在等待连接
  • SYN - SENT: 客户端在发送连接请求后,等待匹配的连接请求,例如客户端发送SYN请求建立连接,但是还没有收到ACK(确认报文),此时的状态.
  • SYN - RECEIVED: 正在等待对方连接的确认(已经收到客户端的SYN,但是还没有收到自己发送的SYN的ACK)
  • ESTABLISHED: 连接已经成功建立
  • FIN_WAIT_1: 等待先前连接的中断请求,在代码层面是主动调用close关闭套接字(TCP已经发送FIN请求,但是还没有收到ACK)
  • CLOSE_WAIT: 主动调用方发送中断请求,被动方收到主动方发送的FIN报文,然后以ACK回应FIN.此时的状态就是CLOSE_WAIT
  • FIN_WAIT_2: 在FIN_WAIT_1状态下收到ACK,处于半关闭状态,在这个状态下应用程序还可以接受数据,但是无法发送数据
  • LAST_ACK: 被动方读取到文件结束标识符后,正在等待调用方的套接字关闭确认(被动方发送FIN报文,等待主动方的ACK报文).
  • TIME_WAIT: 主动方接受FIN报文,并且返回ACK报文后的状态,这个状态保持2MSL(两个主机之间数据单向传输一次的最大时间),这是为了保证在两个传输方向未被接受或者迟到的报文都已经消失,处于TIME_WAIT状态的连接不会被内核释放,在理论上就会保证ACK报文到达(由于连接不会释放,如果此时ACK丢失,那么服务器会重发一个FIN报文,那么客户端收到FIN后,会回应ACK报文).
  • CLOSING: 当双方几乎在同时close()一个SOCKET的话,就出现了双方同时发送FIN报文的情况,这是就会出现CLOSING 状态,表示双方都正在关闭SOCKET连接,这个状态很少见.
  • CLOSED:没有任何连接

注意: 这11个状态并不是客户端和服务端都存在的:

  • 只存在于客户端的状态有: (1)SYN-SENT (2) FIN-WAIT-1 (3) FIN-WAIT-2 (4)CLOSING(5)TIME-WAIT
  • 只存在于服务器端的状态有:(1)LISTEN (2)SYN-RCVD (3)CLOSE-WAIT (4)LAST-ACK
  • 客户端和服务器端共有的状态有: (1)CLOSED (2)ESTABLISHED

大家可以使用命令netstat -ano查看活动连接

大家可以结合这个图来理解:

三次握手

先上总结图:

img

第一次握手: 客户端发送SYN = 1(这是一个同步报文))表示尝试建立连接,seq = x(序号为x,表明传输数据的第一个数据字节的序号为x)

第二次握手: 服务器收到请求后,如果同意,则发送确认报文(ACK = 1,ack = (客户端的seq + 1)),因为需要客户端确认,所以发送信息中有SYN = 1和seq = y.

第三次握手: 客户端收到确定报文后,检查ack是否正确,若正确,客户端会再次发送ack = (服务端seq + 1),seq = x + 1,并且ACK = 1表明连接建立成功.

总结: 在第一次握手时,由客户端发送SYN(seq = x)到服务器,并进入SYN-SENT状态,等待服务端确认报文,第二次握手时,服务端成功接受SYN报文,但是要确认客户端的SYN,所以回应ack = x + 1,即SYN+ACK包,这个是由内核操作的,所以可以共同发送,此时服务器进入SYN-RCVD状态,第三次握手,客户端收到服务端的SYN+ACK包,然后向服务端发送确认包(ack = y + 1),此时客户端和服务端(接受到ACK后)进入ESTABLISHED状态,完成三次握手.

三次握手的意义

  1. 三次握手相当于"投石问路",以确保通信链路是通畅的,为传输的可靠性提供的保障,

  2. 验证了通信双方的发送能力和接受能力是否正常

  3. 让通信双方协商一些参数,例如这里的客户端发送的序号为x,那么服务端返回的确认序号就是x + 1.

  4. 避免资源浪费,如果只有两次握手,在第二次握手后发送确认报文时,由于网络延迟客户端没有收到,所以会重新发送,导致一个客户端建立两个连接,但是第三次握手后,就避免客服端重复发送请求.

四次挥手
img

三次握手是建立连接,TCP是全双工的,所以在关闭连接时,要经过4次挥手来完全关闭客服端和服务端的连接.

注意: A发送FIN(结束报文段)给B,只能终止A->B这个方向没有数据流通,所以只有B向A发送FIN后,B->A方法也没有数据流通,才表明整个TCP连接结束.

第一次挥手:在AB之间的数据传输完毕后,二者都可以释放连接,首先A向B发送FIN = 1(表示该报文为结束报文),表明A没有数据发送给B了,断开A->B的连接吧,seq = u(在自定义协议中谈到过,这是通信结束标识符),进入FIN-WAIT-1状态,等待B的确认报文.

第二次挥手:B接受到A的接受报文,发送确认序号ack = u + 1和序号seq = v给A,B进入COLSE-WAIT状态.

第三次挥手: 如果B还需要发送数据,就继续发送,因为一旦B发送一个FIN,就中断B->A的连接了,发送完毕后,就发送确认序号ack = u + 1和新的序号seq = w的ACK + FIN包,用来关闭B->A的数据流通.B进入LAST-ACK状态

第四次挥手: A接受到FIN结束报文后,如果没有要发送的数据,就向B发送ACK表明B->A的连接已中断,A进入TIME-WAIT状态,这个状态为什么是2MSL在上面讲解过了,时间结束后A进入CLOSED,

下图是TCP状态转换的一个汇总:

虚线表示服务端的状态变化情况 ,实线表示客户端的状态变化情况 .

滑动窗口机制

在确认应答机制中,每一次发送的数据段,都需要回应ACK后,才能继续发送下一个数据段,导致效率低,

对于一发一收的方式性能较差,那么就可以采用为多发多收的方式,其实是把等待ACK的时间重叠在一起了.

说明:

  • 窗口大小指的是不等待发送数据段的最大值.
  • 在收到第一个ACK后,窗口会向后移动,继续发送第五个数据段,依此类推;
  • 操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录哪些数据段没有收到ACK,对收到ACK的数据段,会被从缓冲区中删除.
  • 窗口越大,数据的吞吐量就越大.

在超时重传机制下,滑动窗口中也会存在丢包,分两种情况讨论

情况一:数据包已经抵达,ACK丢了

​ 这种情况下,会根据后面的ACK来进行确认,例如上图中1 ~ 1001的数据段的ACK丢失,但是接受到1001~ 2000数据段的ACK,由于滑动窗口是按照顺序发送的,所以当接受到1001~2000数据段的ACK,就说明1 ~ 2000的数据已经接受了.所以窗口中始终维护的1 ~ 当前接受数据段最大值+1.

情况二:数据包直接丢了

如图分析:

  • 主机A丢失1001 ~ 2000 的数据段,导致主机B接受到2001 ~ 3000时都没有接受到,所以从此时开始向主机A发送"已接受1~1000字节的数据",来提示主机A,我没有1001 ~2000的数据段
  • 在主机B发送三次这样的信息后,主机A终于知道它要的是什么,于是会重新发送1001 ~ 2000的数据段
  • 其实主机B把2001 ~ 7000的数据段接受到存放在内核的接受缓冲区中,所以在收到1001~2000的数据段后,就返回7001.

这种机制也叫做"高速重发控制"

流量控制机制

在滑动窗口机制下,接受端处理数据的速度是有限的,如果发送端发送速率大于接受端处理速率,从而导致接受端缓冲区被充满,这个时候发送端继续发送,就会造成丢包.

所以TCP根据接收端的处理速率来决定发送端的发送速率.这个机制就叫做流量控制.

  • 在TCP字段中有个"16位窗口大小"字段,会在接收端发送ACK时,告诉发送端自己窗口的大小
  • 在接收端发现自己的缓冲区满了,就会把窗口缩小并且把这个信息发送给发送端.
  • 发送端接受这个窗口缩小信息后,就会减少发送数据速率.
  • 如果长时间没有接受到接收端ACK中的窗口减少信息说明窗口为0,发送端就会不会发送数据段,但是需要定期发送一个窗口探测数据段,接收端就会把当前的窗口大小告诉发送端

注意: 窗口大小为16为,并不是窗口最大为16字节,在首部的40字节中的选项还包含一个窗口扩大因子M,实际窗口大小为窗口字段向左移M位.

拥塞控制

首先先了解什么是拥塞,在某段时间,网络中的某一资源需求量超过资源供给量,即供不应求,此时就会导致拥塞,所以要对数据进行流量控制,这里的控制是针对整体的控制,不仅是发送方和接收方,还有中间一系列用来转发的设备.

而滑动窗口协议是指端到端的的通信量控制.

TCP进行拥塞控制的算法有:慢开始、拥塞避免.

慢开始:

主机从小到大逐渐增大发送窗口,即增大拥塞窗口的数值,根据反馈信息,了解当前网络拥挤状况,再决定以多大的速度传输数据

这里慢开始的窗口增长级别是指数级别的,慢开始只是指初使时慢,但是增长速度非常快 ,为了避免窗口增长的太快,所以引入拥塞避免算法

当拥塞窗口大于ssthresh(慢启动阈值)时,窗口增长由指数增长转变位线性增长(每一次cwnd + 1),但是窗口仍然再增大,在增长到出现大量丢包时,就会减少窗口大小为1

  • 当TCP开始启动的时候,慢启动阈值等于窗口最大值
  • 在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置回1

总体流程图:

img
延迟应答

在滑动窗口机制下,接收方接受数据后立即返回响应报文,这时候返回的窗口会十分小.

  • 如果缓冲区的大小为1M,一次接受了500k的数据,如果立即应答,那么返回的窗口为500K.
  • 但实际上处理端处理数据的速度很快,10ms就会把缓冲区的数据接受完毕.
  • 在这种情况下,并没有达到接收端的极限(在摸🐟),此时把窗口扩大一点,它也能够处理下来
  • 此时就可以让接收端等一会才应答,比如等待200ms后缓冲区的数据就会被处理完,响应报文返回的窗口大小就是1M

但是不是所以的包都可以延迟应答,都有所限制

  • 数量限制: 每隔N个包后就应答一次
  • 时间限制: 超过最大延迟时间就应答一次
捎带应答

在延迟应答的机制下,可以把上一次ACK报文和这一次响应报文一起发送,首先要了解,ACK报文一般是由内核发送的(速度快),响应报文是由应用程序发送的(速度慢),二者之间会存在时间间隔,这时候就可以让ACK报文等待一段时间,等待响应报文发送时搭个顺风车

在这里插入图片描述

其他特点
面向字节流

准确的讲:面向字节流是指在读写载荷数据,按照"字节流"的方式读取的,对于TCP数据报,本就是按照一个一个数据报的方式传输的.

缓冲区

在创建一个TCP的Socket时,会在内核中创建一个发送缓冲区和接受缓冲区

  • 调用write时,数据会被写入发送缓冲区.此时根据发送∟大小决定下一步操作
    • 如果发送字节数太短,会在缓冲区中等待,直到缓冲区要满了,或者其他合适时机发送出去.
    • 如果发送字节数太长,就会被拆分成多个TCP数据包发送
  • 在接受数据时,数据是从网卡驱动程序到达内核的接受缓冲区
  • 接收端可以调用read读取缓冲区的数据
粘包问题

这里的粘包指的是"应用层的数据包",在TCP协议中没有如同UDP的"报文长度"的字段,但是它可以对数据按照一定长度分段并标序号,站在传输层的角度上,TCP是一个一个报文传过来的,并且按照序号存放在缓冲区中,但是在应用层的角度下,看到的只是一连串数据,并不知道从哪里开始读取到结束.

在TCP中连接方式有两种,对于短连接,此时不需要考虑粘包问题,因为只有一个TCP数据包,但是对于长连接,会传输多个TCP数据报,此时应用层就无法区分从哪里开始,哪里结束,就会造成粘包问题.

那么如何解决粘包问题呢, 明确包与包之间的边界

  • 约定固定长度读取
  • 使用分隔符明确边界
TCP异常情况
  • 主机断电/网络断开
  • 接收方断电: 发送方尝试发送数据,没有得到对方的ACK,就会重新发送,重发几次后,还是没有收到ACK,就会尝试重新建立连接,如果无法建立连接,就会放弃连接.
  • 发送方断电: 接收方等待发送方的数据,结果没有收到,但是接收方不知道发送方是没有发还是出现故障,所以接收方会一段时间没有接受到数据后,就会定期给发送方发送"心跳包"(保活定时器),相当于接收方发送一个特殊的报文,如果发送方同样返回一个特殊的报文就说明对方正常,如果没有则说明挂了.
  • 进程终止

结束进程,这个过程是先释放进程PCB,然后释放文件描述符表上对应的文件资源(相当于调用close),此时就会触发四次挥手.仍然可以发送FIN.

  • 程序崩溃

即使是崩溃,也会先释放进程PCB,然后释放文件描述符表,仍然会触发挥手,即使进程挂了,但是TCP连接是由内核负责的,所以内核会接手后续挥手的操作

TCP和UDP的对比

  • TCP 是面向连接的传输控制协议,而UDP 提供了无连接的数据报服务;
  • TCP 具有高可靠性,确保传输数据的正确性,不出现丢失或乱序;UDP 在传输数据前不建立连接,不对数据报进行检查与修改,无须等待对方的应答,所以会出现分组丢失、重复、乱序,应用程序需要负责传输可靠性方面的所有工作;
  • UDP 具有较好的实时性,工作效率较 TCP 协议高;
  • UDP 段结构比 TCP 的段结构简单,因此网络开销也小。
  • TCP 协议可以保证接收端毫无差错地接收到发送端发出的字节流,为应用程序提供可靠的通信服务。对可靠性要求高的通信系统往往使用 TCP 传输数据
  • 于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响

提供了无连接的数据报服务;

  • TCP 具有高可靠性,确保传输数据的正确性,不出现丢失或乱序;UDP 在传输数据前不建立连接,不对数据报进行检查与修改,无须等待对方的应答,所以会出现分组丢失、重复、乱序,应用程序需要负责传输可靠性方面的所有工作;
  • UDP 具有较好的实时性,工作效率较 TCP 协议高;
  • UDP 段结构比 TCP 的段结构简单,因此网络开销也小。
  • TCP 协议可以保证接收端毫无差错地接收到发送端发出的字节流,为应用程序提供可靠的通信服务。对可靠性要求高的通信系统往往使用 TCP 传输数据
  • 于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zzt.opkk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值