应用程序间的数据传输UDP协议的特点及

举报
xcc-2022 发表于 2022/07/29 15:21:48 2022/07/29
【摘要】 下面是TCP和UDP的简单程序:简单的TCP网络程序https://blog.csdn.net/qq_37941471/article/details/80738319简单的UDP网络程序 https://blog.csdn.net/qq_37941471/article/details/80726398接着我们通过这两个协议来更直接的理解一下TCP协议和UDP协议:这两个协议其实都属于传输...

下面是TCP和UDP的简单程序:
简单的TCP网络程序
https://blog.csdn.net/qq_37941471/article/details/80738319
简单的UDP网络程序 https://blog.csdn.net/qq_37941471/article/details/80726398
接着我们通过这两个协议来更直接的理解一下TCP协议和UDP协议:
这两个协议其实都属于传输层协议。
这里写图片描述

UDP协议


1. UDP协议端的格式 :

这里写图片描述
`

1. 传输层向应用层交付的过程:解包和分用
2. 如何将有效载荷和报头分离?
 情况一:在应用层中,http协议是通过一个空行来当做分隔符
 情况二: 在下三层(传输层,网络层,数据链路层)中,
        都是通过报头定长的方式来实现报头和数据有效分离。
        这里的报头标准长度为:8字节
3. 传输层中为什么会有源端口号和目的端口号?
   向应用层交付过程中需要端口号来找到应用层的处理程序(进程)
   ( ip地址+端口号(套接字)能够标识网络上的某台主机放入某个进程 )
4. 16位UDP长度:
   表示整个数据报的最大长度。而这个数据报指的是:UDP首部 + UDP数据
5. 16位UDP校验和:
   如果校验和出错,就会直接丢弃
   另外我们可以看出源端口号和目的端口号都是用16位来表示,
   所以说端口号的大小是两个字节(16位),是协议规定的。

2. UDP的特点 :

1. 无连接:
   知道服务器端的IP和端口号就直接进行传输,不需要建立连接(图一);
   图一是没有运行服务器端,直接运行客户端的情况,
   输出内容,收不到服务器端的回应,处于等待阻塞等待状态。
   而tcp是需要连接的,图二就是不运行服务器端直接运行客户端的情况:连接失败
2. 不可靠:
   没有确认机制,没有重传机制;如果因为网络故障该段报文无法发到对方,
   UDP协议层也不会给应用层返回任何的错误信息。
3. 面向用户数据报:
   不能够灵活的控制读写数据的次数和数量
      那么,udp在传输中,会不会出现只发送了一半的报文的情况?
      答:不会。因为应用层交给UDP多长的报文,UDP会原样发送,
          既不会拆分,也不会合并(整包收整包发).
4. 简单快速(高效):
   不会因为维护可靠性而花费时间及成本。
5. 另外传输的数据有上限,64k

图一:
这里写图片描述
图二:
这里写图片描述

3. UDP的缓冲区 :

UDP的socket既能读又能写,即全双工。

没有真正意义上的发送缓冲区:
    调用sendto()会直接将报文交给内核, 
    由内核将数据传给网络层协议进行后续的传输工作;
具有接受缓冲区:
     但是它不能保证UDP报文收到的顺序和发送的顺序一致; 
     并且如果缓冲区满了,接下来到达的报文会被丢弃。

4. 基于UDP的应用层协议 :

  1. NFS:网络文件系统
  2. TFTP:简单文件传输协议
  3. DHCP:动态主机配置协议
  4. BOOTP:启动协议(用于无盘设备启动)
  5. DNS:域名解析协议
    当然也包括自己写的UDP程序中自定义的应用层协议。

TCP协议:


和UDP协议(没有真正意义上的发送缓冲区,具有接受缓冲区)对比,TCP协议是具有接受缓冲区和发送缓冲区的。

1. TCP协议段格式 :

这里写图片描述

1. 源/目的端口号:表示的是从哪来到哪里去
                 为了保证将该报文传到传输层的某一个应用程序(进程)
2. 32位序号/32位确认序号:图中已经说明,而其目的就是:保证报文能够按序到达
3. 4位TCP报头长度:表示该TCP头部的最大长度是15*4=60
    其中一行代表4个字节,而标准的报头是前5行(20个字节;
    而第六行的选项是头部选项,占用40个字节。一共加起来就是60个字。
4. 6位标志位:
   URG: 表示紧急指针是否有效。(通常将其数据称为:带外数据) 
        如果想优先处理那个数据,就将这个标志位置为1
   ACK: 表示确认号是否有效。我们称携带ACK标志的TCP报文段为确认报文段。 
        如果确认,就有可能带着要发送的内容
   PSH: 提示接收端应用程序应该立即从TCP接受缓冲区中读走数据(按序处理),为接受  
        后续数据腾出空间,如果不将接收到的数据读走,它们就会一直停留在TCP报文段。 
   RST: 表示要求对方重新建立连接。我们称携带RST标志的TCP报文段为复位报文段。
        如果服务器端并没有收到请求连接,那么就将这个RST标志位置为1,表示客户端  
        重新请求连接。(告诉客户端连接失败,这个时候有可能做两件事: 
        1.重新建立连接 2.断开之前的连接)
   SYN: 表示请求建立一个新连接。称携带SYN标志位的TCP报文段为同步报文段。
        只有请求连接的时候,ACK=0,这个时候需要收到对方的应答, 
        如果收到了,就会将ACK = 1.
   FIN: 表示通知对方本端要关闭连接了。称携带FIN标志的TCP报文段为结束报文段。 
5. 16位窗口大小:图中有讲
6. 16位校验和:由发送端填充,接收端对TCP报文端执行CRC算法以检验TCP报文段  
             在传输过程中是否损坏(检验部分包括报头和数据部分)。 
7. 16位紧急指针:图中有讲,并且将其要处理的数据叫做:带外数据
8. 选项:40字节的头部选项字段

2. TCP协议的特点 :

总体来说TCP协议会比较复杂,因为要保证可靠性,同时又尽可能的去提高性能。
1. 有连接
   UDP协议知道服务器端的IP和端口号就直接进行传输,不需要建立连接(图一);
   图一是没有运行服务器端,直接运行客户端的情况,  
   输出内容,收不到服务器端的回应,处于等待阻塞等待状态。 
   而tcp是需要连接的,图二就是不运行服务器端直接运行客户端的情况:连接失败
2. 可靠传输
3. 面向字节流

图一:
这里写图片描述
图二:
这里写图片描述

tcp协议最重要的特点:
可靠性:
  1. 校验和
  2. 面向连接
  3. 接受和发送 请求确认 确认应答
  4. 序列号(报文按序到达)
  5. 去重(超时重传中按照序列号实现去重)
  6. 连接管理
  7. 流量控制
  8. 拥塞控制
  9. 面向连接
提高性能:
  1. 滑动窗口
  2. 快速重传
  3. 延迟应答
  4. 捎带应答
  其实拥塞控制主要体现了可靠性,但其实也提高了性能
协议中出现的3个定时器 :
  1. 超时重传定时器
  2. 保活定时器
  3. TIME_WAIT定时器题

下面我们针对上面的问题做以解释:

3. 连接管理机制 :

在我的另外一篇文章的最底下有讲TCP协议的通讯过程:
https://blog.csdn.net/qq_37941471/article/details/80738319#t6

另外:

在正常情况下,TCP是要经过三次握手建立连接,四次挥手 断开连接。
并且,服务器端和客户端不管是在收发报文时,都是基于状态机的。

4. 理解TIME_WAIT状态 :


两方建立连接,如果服务器端先断开连接,而客户端还开着;然后立即重启服务器端,会发现端口地址被占用,无法建立连接,因为主动断开连接的一方有一个等待的过程 ( TIME_WATE )。

服务器先断开连接后:

这里写图片描述
这里写图片描述

我们会发现,突然间断开服务器,而客户端还在连接中,立即重启服务器是不可以的!等一会才可以再次重启服务器。这是等一会的时间就是在四次挥手(断开连接)的时间。

我们用netstat命令看一下:
这里写图片描述

1. TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,
   等待两个MSL(报文最大生存时间)的时间后才能回到CLOSE状态。
2. 我们使用ctrl+c 终止了server,所以server是主动关闭连接的一方,在TIME_WAIT期间仍然不能再次监听同样的server端口
3. MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同,在Centos7默认配置的值是60s.
   可以通过下面的命令来查看msl的值:
   [root@localhost day03_6.18]# cat /proc/sys/net/ipv4/tcp_fin_timeout
    60
   [root@localhost day03_6.18]# 
解决TIME_WAIT状态失败引起的bind失败的方法:

使用setsockopt( )设置socket描述符的SO_REUSEADDR为1,表示允许创建端口号相同但ip地址不同的多个socket描述符。
在Tcp_server.c代码的socket( ) 和 bind( ) 调用之间插入如下代码:

 int opt = 1;
 setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
     int listen_sock = socket(AF_INET, SOCK_STREAM , 0 );// SOCK_DGRAM 表示UDP
     if(listen_sock < 0)
     {   
         perror("socket");
         return 2;
     }
     printf("Socker:%d\n",listen_sock);

     int opt = 1;
     setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
    //2. 命名套接字

    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[2]));//端口号是2位的数
    local.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY可以绑定任意ip

这里写图片描述
我们会发现,突然间断开服务器,而客户端还在连接中,立即重启服务器是可以的。

5. 确认应答机制:


数据( 序列号 ):TCP将每个字节的数据都进行了编号,即为序列号,比如下面的1~1000
确认序列号:每一个ACK都带有对应的确认序列号,告诉发送者,下次应该从哪一个报文开始发。
比如下面的:下一个是1001,这就是确认序列号
1

6. 超时重传机制:


主机A没有收到主机B的确认应答,有两种情况:

1. 主机B没有收到数据:主机A向主机B发送数据过程中,由于网络拥堵等原因,数据无法到达主机B(解决方法:在一个特定的时间内,主机A没有收到B发来的确认应答,就会重发数据)

这里写图片描述

2. 主机B收到数据,但是ACK丢失了:

这样如果主机A重发数据,主机B会收到很多重复的数据,那么TCP协议将如何识别这些重复的包,并且将重复的包丢弃呢?
答:根据之前协议中的字段:序列号,很容易就会实现去重的效果

这里写图片描述

3. 那么如何确定这个超时的时间?

随着网路环境的不同,是有差异的;TCP为了保证无论在任何环境下都能比较高性能的通信,因此动态计算这个最大的超时时间。

7. 滑动窗口:


1. 为什么需要滑动窗口?

答: 提高性能。
        原因:每一个发送出去的数据段,都要收到一个ACK确认应答,
             收到之后再发送下一个数据段;这样数据多的时候,性能会较差。
 如何提高性能:一次发送多条数据。(将串行改成并行)

2. 窗口大小和16位窗口大小的区别:
这里写图片描述

1. 窗口大小:指的是无需等待确认应答而可以继续发送数据的最大值。
           ( 上图中的窗口大小就是:4000个字节 )
2. 16位窗口大小:是告诉对方自己的接受能力
3. 窗口大小:是根据接收端的接收能力(16位窗口大小)而定的窗口大小
1. 发送前4段的时候,不需要等待任何的ACK,直接发送;
2. 收到第一个ACK后,滑动窗口自动向后移动,继续发送第5段的数据;
   依次类推( 如下图 ,下图中是根据数组的下标来确定滑动窗口的大小的)
3. 操作系统内核如何维护滑动窗口?
   答:发送端维护:开辟一个发送缓冲区,来记录哪些数据还没有应答
                 只有确认应答过的数据才能从缓冲区中删除。
4. 窗口越大,网络的吞吐率就越高。

这里写图片描述

8. 如果出现了丢包,如何进行重传?&& 快速重传机制 :


1. 报文比较多,为了提高性能使用滑动窗口的情况下:

情况一 :数据已经抵达,ACK(确认信息)丢了

这种情况就是:一个滑动窗口的大小是4000,前面的3000的确认信息(ACK)某个丢失了,
但是收到了(下一个是4001)的信息,这种情况其实表示主机B已经收到了前4000个数据,
这种ACK丢失没有影响。 

情况二:数据报直接丢了(如下图)
      这种机制被称为“高速重发控制”(也叫作“快重传”)
      1. 怎么会触发快重传机制?
      答:如果发送端连续收到3次一样的确认应答信息
      2. 触发快重传机制后怎么做?
      答:立即重传。并且下一次收到的ACK根据之前的传送情况来决定(如下图的情况)

2. 如果只有一两个报文,根本就不会触发快重传机制:

   因为:快重传机制要收到3个同样的确认应答,才会触发快重传机制。
        这个时候应该触发的是:超时重传机制。

这里写图片描述

9. 流量控制:


1. 为什么需要流量控制?

答: 因为接收端的接受能力(能够处理的数据)是有限的;
    而发送端如果发送的太快的话,接受缓冲区很容易就会被装满;
    这个时候如果发送端继续发送数据的话,则会出现丢包问题。
    继而会出现丢包重传等一些问题;
    所以我们就需要流量控制机制,来防止这种情况发生。

2. 流量控制的概念:

TCP支持根据接受端的处理能力,来决定发送端发送数据的速度,这种机制叫做流量控制(Flow control)
3. 怎么做到流量控制 ?:

TCP首部的16位窗口大小的含义就是告诉发送端自己的接受能力

1. 接受端 :将自己可以接收的缓冲区大小放入TCP首部的"16位窗口大小"中;
          然后通过ACK通知发送端。
          如果一旦发现自己的缓冲区变少了,就将窗口大小的值变小;
2. 发送端 :根据对方的"16位窗口大小"来控制自己的发送速度;
          如果发现窗口大小变小了,就减慢自己的速度;
3. "16位窗口大小"和 网络的吞吐量成正比 :
          窗口大小字段的值越大,网络的吞吐量就越高,传输效率就越高
4. 接收端 :如果发现接受缓冲区满了,就将窗口大小置为0
5. 发送端 :这个时候发送端看到之后,就不会再去发送数据( 防止丢包 )
           而这个时候,发送端需要定期的去探测接受端;将自己的窗口大下高速发送端

具体的实现过程如下图:
这里写图片描述
4. 16位的数字大小是65535,那么TCP窗口大小最大65535吗?

答: 不是。
   TCP首部里面有一个选项,选项中包含了一个窗口扩大因子M;
   实际上的窗口大小最大是:窗口字段左移M位;
   当然最后的结果肯定是小于等于65535的

10. 拥塞控制:


1. 为什么要拥塞控制?

答:因为TCP在为了提高效率:
   1. 根据接收端的接收能力("16位窗口大小")来确定发送端的滑动窗口大小

   而又为了可靠性,即可靠高效的传送大量的数据时 :
   1. 我们需要考虑网络状态
   2. 如果网络拥塞,贸然的去发送大量的数据,必定会丢包,丢大量的数据

   根据丢包的多少,来确定是哪里出了问题?
   1. 丢失了少量的数据 :我们会认为是发送端发错了,漏发了,这个时候进行(重传处理)
   2. 丢失了大量的数据 :那么就有可能是网络拥塞的可能;
                      如何避免这种情况,引出了拥塞控制机制

2. 怎么进行拥塞控制?

  1. 首先:先发少量的数据,去摸清当前网络的拥塞状态
  2. 再决定按照多大的速度来传输数据
    这里写图片描述
一切的基础还是慢开始,这种方法的思路是这样的:

 1. 发送方维持一个叫做“拥塞窗口”的变量
    该变量和接收端的窗口大小共同决定了发送者的发送速度;

 2. 当主机开始发送数据时,避免一下子将大量字节注入到网络,
    造成或者增加拥塞,选择发送一个1字节的试探报文;

 3. 当收到第一个字节的数据的确认后,就发送2个字节的报文;

 4. 若再次收到2个字节的确认,则发送4个字节,依次递增2的指数级;

 5. 最后会达到一个提前预设的“慢开始门限”,
   比如24,即一次发送了24个分组,此时遵循下面的条件判定:

   *1. cwnd < ssthresh, 继续使用慢开始算法;

   *2. cwnd > ssthresh,停止使用慢开始算法,改用拥塞避免算法;

   *3. cwnd = ssthresh,既可以使用慢开始算法,也可以使用拥塞避免算法;

 6. 所谓拥塞避免算法就是:每经过一个往返时间RTT就把发送方的拥塞窗口+1,
                       即让拥塞窗口缓慢地增大,按照线性规律增长;

 7. 当出现网络拥塞,比如丢包时,将慢开始门限设为原先的一半,
    然后将cwnd设为1,执行慢开始算法(较低的起点,指数级增长);

3. 发送数据时,需要考虑哪两个方面?

1. 接收端的"16位窗口大小"( 即接受端的接受能力 ) :
   根据窗口大小,来确定滑动窗口大小,并且还能通过流量控制来实现可靠性
2. 考虑网络的拥塞情况 :
   根据拥塞窗口,来控制传输的速度
总结:我们借用滑动窗口来提高效率的时候,同时需要:流量控制 和 拥塞控制
     来维护可靠性,从而实现高效又可靠的传输。

11. 延迟应答:


1. 目的:

1. 提高效率
2. 为了给发送端回应一个更大的"16位窗口大小"
   (窗口大小越大,网络的吞吐量就越大,传输的效率也就越高)

2. 如果立即应答,会怎么样?:

1. 如果接收缓冲区的大小为1M,而一次只收到了500K的数据,
   这个时候如果立即应答,发送端接收到的窗口大小就是500K(接收缓冲区剩余的空间)
2. 而如果延迟应答,等一会,有可能应用层的处理端会很快的处理缓冲区的数据,
   那么我们回应给发送端的窗口大小就是1M.

3. 是不是所有的包都可以延迟应答?

我们的目的就是提高效率,然后如果所有的包都延迟应答的话,有可能反而起到了反的作用

这个时候,我们应该怎么把我延迟应答的时间呢?
1. 数量限制 :每隔N个包,延迟应答一次
2. 时间限制 :每隔一段时间,延迟应答一次
 而这个时间根据操作系统的不同,时间也不同;
 一般N取2;时间取200ms

12. 捎带应答:


1. 目的:提高效率
2. 什么情况下需要捎带应答?

 当客户端和服务器端在应用层“一发一收”的时候
 比如 :
 客户端 :how are you?
 服务器端 : Fine,thank you!
 这个时候,服务器端给客户端的确认应答ACK可以搭一个顺风车,
         同"Fine,thank you!"一起回给客户端

这里写图片描述

13. 面向字节流:


TCP的一个连接,具体发送缓冲区,又有接受缓冲区;
并且对于一个连接,既可以读数据,又可以写数据;这个概念叫做全双工。

由于缓冲区的存在,TCP程序的读和写不需要一一匹配
1. 写100个字节的数据 :
   1. 可以调用一次的write,直接一次写入100个字节
   2. 也可以调用100次的write,一次写入1个字节
2. 读100个字节的数据 :
   不考虑写入的时候是怎么写入的
   1. 可以调用一次的read,直接一次读100个字节
   2. 也可以调用100次的read,一次读1个字节

14. 粘包问题:


1. 为什么会有粘包问题?

1. UDP的报头中有一个"16位的报文长度"的字段,这样会很明确的清楚数据的边界
   而TCP的报头没有这个字段
2. 站在传输层的角度 :
   TCP是一个报文一个报文按照顺序放在缓冲区中的
3. 站在应用层的角度 :
   看到的只是一连串连续的字节数据。无法确认边界

2. 如何避免粘包问题?

明确边界
1. 对应定长的包 :保证每次都按照固定的大小去读取
   比如Request结构,就是固定大小的;
   每次读取的时候,都是从头开始读取一个sizeof(Request)的大小
2. 对于变长的包 :
   1. 可以在包头的位置,约定一个包总长度的字段,从而知道包的结束位置
   2. 当然也可以在包与包之间用分隔符来分界
    (这个是由应用层实现的,也属于一个自己的应用层协议)

3. 对于UDP协议来说,会不会出现粘包问题?

答: 不会。
    1. 首先,UDP协议的报头中有一个"16位的报文长度"的字段,
            这样会很明确的清楚数据的边界
    2. 其次,UDP协议是面向数据报的,它是整包收整包发的
            既不能拆分,又不能合并;不会出现"半个"的情况

15. TCP异常情况:


1. 进程终止 :进程终止会释放文件描述符,仍然可以发送FIN(四次挥手),
             和正常关闭没有什么区别;
2. 机器重启 :和进程终止的情况相同
3. 机器断电/网络断开:
     1. 比较突然的情况,接收端会认为连接还在,
       一旦接收端有写入操作,会发现连接已经不再了,就会进行reset.
     2. 即使没有写入操作,TCP自己也内置了一个保活定时器,会定期的询问对方还在不在;
        如果不在的话,就会把连接关闭,释放。(这个不会有四次挥手)

16. 基于TCP的应用层协议:


1. HTTP
2. HTTPS
3. SSH
4. Telnet
5. FTP
6. SMTP

TCP/UDP对比:


我们说TCP是可靠连接,那么TCP就一定优于UDP吗?
答: 不是的。
     根据应用场景,来选择更优的协议
     1. TCP协议的应用 :用于可靠传输的情况
                      比如:文件传输,重要状态更新的场景
     2. UDP协议的应用 :用于高效传输和实时性要求较高的通信领域
                      比如:早期的QQ,视频传输,另外还可以用于广播

UDP不能实现可靠性,但是如何实现呢?

通过应用层来实现(谁有谁来实现)

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。