博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UDP、TCP协议——Linux网络编程
阅读量:3945 次
发布时间:2019-05-24

本文共 6414 字,大约阅读时间需要 21 分钟。

UDP协议

UDP的全称是用户数据报协议(User Datagram Protocol),UDP为应用程序提供了一种无需建立连接就可以发送数据包的方法。

UDP协议头部格式

在这里插入图片描述

  1. 源端口:发送数据包的应用程序所使用的端口
  2. 目的端口:接收数据包的应用程序使用的端口
  3. 数据长度:表示UDP数据包的长度,包含UDP头部长度和UDP数据长度;UDP报文头长度是8个字节,所以这个值最小为8,最大长度为65535字节
  4. 校验和:检验UDP数据在传输过程中是否有损坏,如果有损坏,则不会提交给应用层,而是直接丢弃。

如何通过检验和来计算是否有数据损坏?

将UDP数据分为多个16比特位的数据,对除了16位检验和的其他16比特位进行相加,如果出现数据溢出,需要进行回卷(将越界的位和低16位进行相加),对加起来的结果取反码,存储在检验和中;

接收方收到数据之后,将所有的16比特位进行相加,如果结果是1111 1111 1111 1111则认为数据是没有损坏的。

TCP协议

TCP的全称是Transmission Control Protocol,传输控制协议,是一种面向连接的协议;

TCP连接是全双工服务的,主机A与另一个主机B存在一条TCP连接,那么应用数据就可以从主机A流向主机B的同时,也从主机A流向主机B;

实际上TCP的每一段都会有发送缓存和接收缓存,TCP会先将数据临时存储在发送缓存中,在合适的时间发送到对端的接收缓存中;

报文段:TCP会将要传输的数据分为多个块,然后向每个块添加TCP头部,这样就形成了一个报文段,报文段可以传输的数据是有限的,不能超过MSS(最大数据长度)

TCP协议头部格式

在这里插入图片描述

  1. 源端口:发送网络包的程序的端口号
  2. 目的端口:接收网络包的程序的端口号
  3. 序列号:在建立连接时,由双方生成的随机数作为其初始值,通过SYN包传给接收端主机,每发送一次数据,就累加一次数据字节数的大小,用来解决网络包乱序问题
  4. 确认应答序号:指下一次期望收到的数据的序列号,发送到收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收,用来解决不丢包的问题
  5. 首部长度:表示的范围00001111(0x00xF),用来表明TCP首部中32bit的数目,通过它可以知道一个TCP包它的用户数据是从哪里开始的,TCP首部长度=4bit转换为十进制的数值*4(字节)
  6. 保留:该字段为保留,未使用,值都为0
  7. 标志位:
    1. URG:紧急标志位,通知接收端在处理其他包之前优先处理接收到的紧急报文
    2. ACK:表示数据被成功接收,确认应答字段变为有效
    3. PSH:通知接收端处理接收的报文,而不是将报文缓存在buffer中
    4. RST:表示TCP连接出现异常必须强制断开连接
    5. SYN:表示希望建立连接,并在序列号字段进行序列号初始值设定
    6. FIN:表示不再会有数据发送,希望断开连接
  8. 窗口大小:指的是接收窗口,最多能接收的字节数
  9. 校验和:检查数据在传输过程是否出现错误,由发送端进行计算并存储,接收到收到后进行验证
  10. 紧急指针:只有当URG标志位为1时紧急指针才有效;紧急指针是一个正的偏移量,和序号字段相加表示紧急数据的最后一个字节的序号
  11. 选项:长度不定,但是必须是32bit的整数倍

TCP的特点

面向连接

TCP三次握手

在这里插入图片描述

  1. 一开始,客户端和服务端都处于CLOSED状态,然后服务端主动监听某个端口,处于LISTEN状态
  2. 客户端将随机初始化的序列号x填入TCP头部的序列号字段,同时把SYN标志位置为1,接着把SYN报文发送给服务端,表示向服务端发起连接,之后客户端处于SYN_SENT状态
  3. 服务端接收到客户端的SYN报文后,先将自己随机初始化的序列号y填入TCP头部的序列号字段,然后在TCP头部的确认应答号字段填入x+1,接着把SYN和ACK标志位置为1,把该报文发送给客户端,只有服务端进入SYN_RCVD状态
  4. 客户端在收到服务端的SYN+ACK报文后,还要向服务端回复一个应答报文,首先将TCP头部的ACK表示置为1,然后在确认应答号字段填入y+1,最后将报文发送给服务端,之后客户端处于ESTABLISHED状态
  5. 服务端在接收客户端的ACK报文之后,也进入ESTABLISHED状态

为什么是三次握手?

  1. 为了防止旧的重复连接初始化造成混乱;
    1. 客户端连续发送多次SYN建立连接的报文,在网络堵塞情况下:一个旧SYN报文比新的SYN报文提早到达了服务端;那么此时服务端就会回一个SYN+ACK报文给客户端;客户端收到后可以根据自身的上下文,判断这是一个历史连接,那么客户端就会发送RST报文给服务端,表示终止这一次连接
    2. 但是,如果是两次握手,就不能判断当前连接是否是历史连接。
  2. 同步双方初始序列号
    1. TCP的通信双方都会维护一个序列号,当客户端发送携带初始序列号的SYN报文时,需要服务端回复一个ACK应答报文,表示客户端的SYN报文已经被服务端成功接收,那么当服务端发送初始序列号给客户端的时候,依然需要得到客户端的应答,这样才能确保双方的初始序列号得到可靠的同步。
    2. 而两次握手只能保证一方的初始序列号能被对方接收成功,无法保证双方的初始序列号都能被确认接收。
  3. 避免浪费资源
    1. 如果只有「两次握手」,当客户端的 SYN 请求连接在网络中阻塞,客户端没有接收到 ACK 报文,就会重新发送 SYN ,由于没有第三次握手,服务器不清楚客户端是否收到了自己发送的建立连接的 ACK 确认信号,所以每收到一个 SYN 就只能先主动建立一个连接,就会建立多个冗余的无效链接,造成不必要的资源浪费。
  4. 三次握手就已经是理论上最少的可靠建立,所以不需要浪费更多的通信次数。

TCP四次挥手

在这里插入图片描述

  1. 客户端打算关闭连接,先将TCP首部的FIN标志位置为1,然后在序列号字段填入当前的序列号x,最后将报文发送给服务端,之后客户端进入FIN_WAIT1状态
  2. 服务端收到客户端发送的FIN报文后,就会向客户端回复一个ACK报文,先将TCP头部的ACK标志位置为1,然后在确认应答号字段填入x+1,然后服务端进入CLOSED_WAIT状态
  3. 客户端在收到服务端的ACK应答之后,进入FIN_WAIT2状态
  4. 服务端等待数据处理完之后,也会向客户端发送FIN报文,先将TCP首部的FIN标志位置为1,然后在序列号字段填入当前的序列号y,之后服务器进入LAST_ACK状态
  5. 客户端在收到服务端的FIN报文后,就会向服务端回复一个ACK报文,先将TCP头部的ACK标志位置为1,然后在确认应答号字段填入y+1,然后客户端进入TIME_WAIT状态
  6. 服务器收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭
  7. 客户端在经过2MSL时间后,也会进入CLOSED状态,至此客户端也完成连接的关闭

为什么需要挥手四次?

  1. 关闭连接时,客户端向服务端发送 FIN时,仅仅表示客户端不再发送数据了但是还能接收数据。
  2. 服务器收到客户端的FIN报文时,先回一个 ACK应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN报文给客户端来表示同意现在关闭连接。

为什么TIME_WAIT等待的而时间是2MSL?

  1. MSL,最大报文生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
  2. 举个例子:如果服务器没有收到断开连接后客户端发送的ACK报文,就会触发超时重传机制重新发送FIN报文,另一方接收到FIN后,会重发ACK给服务端,这样一来一回刚好是2MSL

为什么需要TIME_WAIT状态?

  1. 等待足够的时间以确保最后的ACK能被被动关闭方接收,使其正常关闭。
  2. 四次挥手的最后一个ACK报文如果在网络中被丢失了,此时客户端TIME_WAIT过短或者没有,就直接进入了CLOSED状态,那么服务端则会一直处在LAST_ACK状态。

可靠传输

确认应答机制

  1. 当发送方将数据发出之后会等待接收方的响应,如果有确认应答ACK,说明数据已经成功到达对端;反之,则数据很可能会丢失。

超时重传机制

  1. 消息发送在方发送一条消息之后,就会设定一个计时器,当超过指定时间之后,还没有收到对方的ACK确认应答报文,就会重发该数据。
  2. 超时重传的时间用RTO表示,RTO=2*RTT
  3. RTT就是数据从网络一端传送到网络另一端所需的时间,也就是报文往返时间
  4. 预测下一个要发送数据的RTT=RTT(当前)×i+RTT(前一个)×(i-1),默认情况下i=0.9,利用这个预测的RTT,计算超时重传时间RTO
  5. 不管是数据丢失还是确认报文丢失,对于消息的发送方而言,都会在RTO时间之后进行重传

滑动窗口机制

  1. 为什么有滑动窗口?
    • 因为有确认应答机制,每发送一个数据,都要进行一次确认应答,当上次个数据,包收到了应答之后,才可以发送下一个。这种方式有一个缺点:数据包的往返时间越长,通信的效率就越低。
  2. 为了解决这个问题,引入了窗口的概念,窗口的大小就是指无需等待确认应答,而可以继续发送数据的最大值
  3. 窗口的实现实际上就是在操作系统开辟的一个缓存空间,发送发在等到确认应答之前,必须在缓冲区中保留已发送的数据,如果按期收到确认应答,数据就可以从缓冲区中清除。
  4. 滑动窗口是TCP进行流量控制的一种手段:对于接收方而言,告诉发送发自己可以接受的缓冲区大小,以此来控制发送发发送数据的大小,从而达到拥塞控制的目的。

拥塞控制机制

  1. 为什么会用拥塞控制?
    • 在网络出现拥堵时,如果继续发送大量的数据包,可能会导致数据包延时、丢失,这时TCP就会重传数据,但是一重传就会导致网络的负担更加严重,于是就会导致更大的延迟和更多的丢包,这个情况就会进入恶性循环;拥塞控制,控制的目的就是避免发送方的数据填满整个网络

为了在发送方调节所要发送数据的量,定义了一个拥塞窗口 cwnd,是发送方维护的一个状态变量,会根据网络的拥塞程度动态变化。

**拥塞窗口的大小=min(发送窗口swnd, 接收窗口rwnd);**只要网络中没有出现拥塞,cwnd就会增大,出现拥塞,cwnd就会减小;

只要发送方没有在规定时间内接收到ACK应答报文,也就是发生了超时重传,就会认为网络出现了拥塞。

  1. 慢启动

    1. 慢启动就是一点一点的提高提高发送数据包的数量,当接收方每收到一个ACK,拥塞窗口cwnd的大小就会加1,发送数据包的个数是呈指数增长的;
      在这里插入图片描述
    2. 慢启动门限ssthresh状态变量(一般来说ssthresh的大小时65535字节),当拥塞窗口大小<慢启动门限时,使用慢启动算法;当拥塞窗口大小>慢启动门限时,使用拥塞避免算法
  2. 拥塞避免

    1. 当拥塞窗口cwnd超过慢启动门限,就会进入拥塞避免算法;每当收到一个ACK时,cwnd增加1/cwnd
      在这里插入图片描述
    2. 拥塞避免算法就是将原本慢启动算法的指数增长变成了线性增长,还是增长阶段,但是增长速度缓慢了一些。这么一直增长着后,网络也会慢慢进入了拥塞状况,就会出现丢包现象,这时就需要对丢失的数据包进行重传。
  3. 快重传

    1. 快重传是相对于超时重传而言的,发生超时重传,慢开始门限sshresh=cwnd/2;拥塞窗口cwnd重置为1

      在这里插入图片描述

    2. 当接收方发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传。

    3. cwnd=cwnd/2,拥塞窗口设置为原来的一半

    4. 慢开始门限等于拥塞窗口大小

  4. 快恢复

    1. 快重传和快恢复算法一般同时使用,如果能够一连串收到三个重复的ACK确认包,会认为网络拥塞不是很严重,所以进入快恢复算法,拥塞窗口cwnd=慢开始门限+3(3的意思是确认有3个数据包被收到了)
      在这里插入图片描述
    2. 重传丢失的数据包,如果在收到重复的ACK,那么cwnd增加1;如果收到新数据的ACK后,设置cwnd=ssthresh,接着进入拥塞避免算法

捎带应答机制

  1. 为了减少网络当中的数据量,当接收方接收到一个数据之后,发出确认的时候,是随着接收方给发送方的数据一起发送的。

延时应答机制

  1. 延时应答并不是不应答,而是不立即进行确认,在接受方收到数据之后,等待200ms,等应用层的程序将接收缓冲区中的数据读走,从而让在返回的时候,尽可能的告诉发送发自己的接收能力比较大。

保活计时器

  1. 双方每收到一次对端的信息,就会将计时器清零复位
  2. 如果计时器超时之后,对端仍然没有反应,则发送探测报文
  3. 如果探测报文有ACK回应,会将计时器复位,
  4. 如果探测报文没有响应,一般来说间隔的默认时间为75秒,连续10次都没有响应,会认为对端发生故障,强行终止连接。

流量控制

当TCP建立连接后,发送方发送的数据就会到达接收方的接收缓冲区中,接收方并不会立即读取缓冲区中的数据,需要等待操作系统分配时间片。如果此时发送方发送数据过快,而接收方接收数据过慢的话,接收方中的缓冲区就会溢出。流量控制就是用于消除缓冲区语出的情况。

接收端主机向发送端主机通知自己可以接收数据的大小,发送端会发送不超过这个限度的数据,这个大小限度就是窗口大小。TCP头部的窗口大小

发送端主机会定期发送一个窗口探测包,这个包用于探测接收端主机是否还能够接受数据,当接收端的缓冲区一旦面临数据溢出的风险时,窗口大小的值也随之被设置为一个更小的值通知发送端,从而控制数据发送量。

面向字节流

TCP不会自动插入记录标志或者消息边界,这意味着TCP没有限制应用程序的写范围。发送端分两次发10字节和30字节,接收端可能会以两个20字节的方式读入。这就引入了新的问题TCP粘包

如何解决TCP粘包问题?

  1. 通信双方按照约定的数据长度来进行传输,这样可以稍微解决TCP粘包问题,但是不能应对复杂的状况;比如:一个通信当中有多个定长的数据结构或者没有定长的数据结构
  2. 数据包头+数据+分隔符,数据包头中可以获取到数据的长度,而分隔符可以找到下一条数据的起始位置,分隔符就起到了定义数据边界的作用

TCP和UDP的区别

TCP协议是面向连接的、可靠的、全双工的、基于字节流的传输层协议。

面向连接:TCP协议必须在通信双方建立连接之后才可以进行通信

可靠的:TCP协议在数据的传输中由丢失重传、流量控制、拥塞控制机制来保证可靠

全双工:通信双方都可以发送数据和接收数据

基于字节流:举个例子:发送端分两次发10字节和30字节,接收端可能会以两个20字节的方式读入,数据可以随意存取

UDP协议是面向无连接、不可靠、非全双工、基于数据报的传输层协议。

面向无连接:在数据传输过程中双方不需要建立连接

不可靠:如果数据丢失,不会保证数据到达对端

非全双工:由于不需要保证连接,可以是一对一、一对多、多对多的数据传输

  1. 连接:TCP是面向连接的传输层协议,传输数据先要建立连接;UDP是不需要连接的,即刻传输数据
  2. 服务对象:TCP是一对一的两点服务,即一条连接只有两个端点;UDP支持一对一、一对多、多对多的交互通信
  3. 可靠性:TCP是可靠交付数据的,数据可以没有差错、不丢失的到达;UDP不保证可靠交付数据
  4. 拥塞控制、流量控制:TCP有拥塞控制和流量控制,保证数据传输的安全性;UDP即使网络已经很拥堵了,也不会影响UDP的发送速率
  5. 首部开销:TCP的首部长度比较长,固定长度20字节,还有可变长度的选项字段,会有一定的开销;UDP首部只有8个字节,并且是固定不变的,开销较小

TCP 协议是面向连接的,其需要三次握手才可以建立连接,还可以做到丢失重传、顺序控制、拥塞控制、流量控制等功能,并且保证连接的可靠性,而 UDP 协议不需要考虑那么多,其只需要尽快的将应用程序的报文传递给网络层便好,所以总结就是 TCP 协议主要用于那些需要可靠通信的,对连接的速度要求相对来说不那么高的情况,而 UDP 协议用在那些需要快速进行通信,不需要保证通信可靠的场合。

转载地址:http://wbowi.baihongyu.com/

你可能感兴趣的文章
什么话不可以和上司讲
查看>>
请学会淘汰你的上司
查看>>
以人为本
查看>>
全球分布式创新:企业致胜的关键
查看>>
上司最恨员工哪十大"罪行"
查看>>
和上司沟通必备8个黄金句
查看>>
竹笋和榕树的管理学
查看>>
让“抱怨”促进公司进步
查看>>
职场“站队”你站对了吗?
查看>>
培养员工能力与责任
查看>>
细分市场制胜
查看>>
空降兵变革是怎样失败的
查看>>
伟大决策的6大基石
查看>>
MTK编译笔记
查看>>
深入理解各种指针
查看>>
Android的SeekBar
查看>>
SMS 和 MMS 在输入字母的响应不一致
查看>>
如何判断手机是否处于漫游状态?
查看>>
恢复出厂设置时删除手机上所有联系人
查看>>
根据Sim卡的插卡情况过滤通话记录
查看>>