【网络】对于我前面UDP博客的补充

UDP

  • 前言
  • 正式开始
    • UDP报文
      • UDP报文
        • 如何将UDP报文和报头进行分离和封装
        • UDP如何将有效载荷交付给上层
        • 如何提取出完整报文
        • 报头是啥
        • 报头中的检验和
      • UDP的特点
      • IO接口
      • 乱序问题
      • UDP是全双工的
      • 注意事项
      • 基于UDP的应用层协议
    • 再次谈论端口
      • 五元组
      • 端口号范围划分
      • netstat
      • xargs

在这里插入图片描述

前言

本篇比较偏理论。基于我前面一篇UDP实践的博客进行补充:【网络】网络编程入门篇——了解接口,快速上手,带你手搓简易UDP服务器和客户端(简易远端shell、简易群聊功能以及跨平台群聊)

主要讲解内容有:

  1. UDP协议报头讲解
  2. UDP协议缓冲区、注意事项等
  3. 五元组
  4. netstat命令讲解

正式开始

UDP报文

下面根据以下内容进行讲解:

  1. 任何协议都要解决两个问题:
    a. 如何分离/封装报头和报文
    b. 如何交付有效载荷
  2. 理解UDP报文本身
  3. 详谈具体报文字段

UDP报文

很简单,就这张图:
在这里插入图片描述

加点东西:
在这里插入图片描述

上面的8字节就是报头,存储了四个字段,每个字段两个字节。

很多教材上都有这张图,但是有的书上详细讲了,有的书没有讲,这里我来讲讲。

如何将UDP报文和报头进行分离和封装

采用定长报头的策略,UDP的报头为8字节的固定长度报头,对端传输层只需要将前8个字节提取出来,剩下的就是有效载荷。(等会说怎么提有效载荷)
在这里插入图片描述

无论是我前面博客中HTTP中用空行来区分报头和有效载荷,还是这里的用定长报头来区分报头和有效载荷,都是协议,双方都要严格遵守,那一层没有遵守哪一层就是一个无用的报文,无法向上交付。

UDP如何将有效载荷交付给上层

提取出报头后,其中有一个字段为目的端口号:
在这里插入图片描述

就通过这个目的端口号进行向上交付,因为进程bind了端口号,我前面写服务端的时候每次端口类型都是uint16_t,即2字节,因为协议中端口号是16位的。

如何提取出完整报文

先读固定长度的报头,报头中有16位的UDP长度字段:
在这里插入图片描述

这个16位的udp长度就是整个报文的长度,假如说是x,整个报文长度为x,报头长度位8,那么有效载荷的长度就是x - 8。读完报头后,再往后读x - 8个字节就行。

所以UDP具有将报文一个一个正确接收的能力。

报头是啥

报头其实就是一个结构体:

struct udp_hdr
{uint32_t src_port:16;uint32_t dst_port:16;uint32_t udp_len:16;uint32_t udp_check:16;
}

用结构体实现位段,如果你不懂位段的话可以看看我这篇博客:【C进阶】自定义类型。

再看一下这张图:
在这里插入图片描述

这里为什么要四字节为一行,因为结构体中用的类型是uint32_t,也就是4个字节,这里4个字节就是报头的宽度,所有的报头其实就是一个结构体类型。

封装一个报头,当应用层发来一个报文(就是传输层的有效载荷)时,传输层只需要定义一个udp_hdr对象,将对象中的字段填好,源端口、目的端口、报文长度(应用层的报文大小 + 8)、检验和,然后将这个对象中的数据拷贝到内核的缓冲区中就行。看图:
在这里插入图片描述

向上交付的时候就定义指针就行,报文长度和报头长度都有了,就根据这两个长度读取就行。

这里只是简单的原理,os真正做起来的话要比这复杂的多,毕竟要考虑大小端、平台位数等问题,还是很复杂的。

报头中的检验和

这个检验和不细讲了,说一下有啥用。

接收方UDP检验成功就向上交付,检验失败报文就直接丢弃了,发送方不知道、不重传、不关心。

UDP的特点

其实我前面那篇UDP的博客中也讲过了,这里就再说一下。

  • 无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接;

如果你看了我前面手搓UDP服务器和TCP服务器的话,你一定懂这句话是什么意思。

因为UDP的服务器只需要这几步:

  1. 创建套接字
  2. bind绑定端口号
  3. recvfrom接收客户端请求并用sendto进行响应

而TCP的服务器是这样的:

  1. 创建套接字
  2. bind绑定端口号
  3. 设置套接字为listen状态
  4. 接收连接
  5. recv/read获取客户端请求并通过write/send进行响应

这里UDP要比TCP少了listen和接收连接这两步,也就是UDP不需要建立连接。

  • 不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层返回任何错误信息;

下面我截一下前面我UDP博客中的一段话:

屏幕前的你先不要拿这一点来判断谁好谁坏。TCP和UDP都能够存在说明是都能被接受的,各有各的特色。
  先说点UDP不好的,UDP会出现丢包问题,TCP不会出现。不过现在的网络出现丢包问题概率并不大,即使出现了大部分场景下也是可以容忍的。先不要对UDP产生偏见,等会讲的时候你就知道为啥了。
  二者的可不可靠只是二者的特点。并不是单方的缺点。
TCP比UDP可靠,那么TCP就要做更多的工作,可靠性是要靠大量的编码和数据处理工作来实现的,所以TCP想要保证可靠性就一定会使得其在数据通信时为了可靠性而设计出更多的策略,如面向连接、确认应答、超时重传、流量控制、拥塞控制等机制,而这些机制都要靠TCP协议自己来完成,所以说虽然保证了可靠性,但是也就导致了该协议更复杂,维护起来成本更高。

此时UDP就可以对TCP说:咋俩都是协议,你把自己搞那么累干嘛,丢包就丢包了,心放大点,这都不是事,所以UDP只要把数据交给下层就行了,然后就啥也不用管了。而TCP就得管一大堆事,即TCP更安全,UDP更简单。

但是我们大部分情况下传输层协议用的是TCP。像直播、视频这种数据可以用UDP,比如我们有时候看着直播 / 视频时突然卡一下/没声了/屏幕花了等等问题,就可能是因为传输层用的是UDP协议导致丢包了,但是这样就卡一两秒对整体的观看体验影响不大(足球比赛快要进球的时候卡了当我没说😅)。不过有钱的公司也在直播或视频这种资源上也可以用TCP协议,不过TCP协议花费更多,但是能够保证数据的安全,客户能有更好的体验。

  • 面向数据报: 不能够灵活的控制读写数据的次数和数量

IO接口

前面TCP和UDP中IO的接口本质上都是拷贝函数。

TCP的 write、send和read、recv。
UDP的 sendto和recvfrom。

都是拷贝函数。

在这里插入图片描述

所以这里的wirte、send、sendto都不是直接将数据发送到网络当中的,而是将数据拷贝到了内核缓冲区中就完事了,后续工作都是os做的。

TCP和UDP是传输层中应用最广泛的协议,而发送缓冲区(UDP不需要,等会说)和接收缓冲区是由传输层提供的,传输层决定什么时候发,发多少,出错了怎么办的问题,我们无法决定这些问题,就像寄快递一样,你只是把东西交给了快递公司,至于快递啥时候发是快递公司的事情,不是我们操心的。

UDP不需要发送缓冲区,调用sendto只是将数据拷贝给os,os会立即将数据经过网络层、数据链路层发送出去,所以对于发送缓冲区没有特别强的需求。

但是UDP需要接收缓冲区,UDP上面是应用层,应用层就是用户,也就是程序员,需要手动调用recvfrom,但是如果程序员来不及调用呢?同一时刻服务端可能会接收到很多的UDP报文请求,如果某些报文来不及接收,就会先放到接收缓冲区中,所以UDP需要接收缓冲区,但如果缓冲区满了,那么后面到来的报文会被直接丢弃。

乱序问题

如果某一时刻客户端发送了5个报文,如果是按照ABCDE的顺序来发的话,可能会出现接收到的报文为BDCEA的顺序,就像我们在某宝上下单一样,同一天下的单,后面收到的时间不一样,顺序也不一样。

UDP乱序问题通常是因为路由之间的存储转发引起的。解决方法是在发送端的数据段中加入数据报序号的方式,只需要在接收方对数据的头端进行简单排序处理即可。具体步骤如下:

  1. 在发送端的数据段中加入数据报序号。
  2. 接收方接收到数据后,将数据报文按照序号进行排序。
  3. 将排序后的数据报文进行组装,得到完整的数据。

需要注意的是,如果数据报文丢失,可能会导致数据报文序号不连续,因此需要在接收方设置一个超时时间,如果在超时时间内没有收到连续的数据报文,则需要重新请求发送方发送数据报文。

不过这里的做法已经很像TCP了,下一篇博客我会详细讲解TCP。

UDP是全双工的

一个文件描述符,再多线程场景下既可以读也可以写,如何保证呢?
只需要读写缓冲区不冲突就行。

UDP虽然没有发送缓冲区,但是发送时并不会影响接收缓冲区,所以支持全双工。

至于全双工和半双工是啥我实在是不想讲了,前面博客中说了好几次了,不懂的同学搜一下或者翻一下我前面的博客吧。

后一篇要讲的TCP也是全双工的。

注意事项

我们注意到, UDP协议首部中有一个16位的最大长度. 也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部)。然而64K在当今的互联网环境下, 是一个非常小的数字。如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装。

基于UDP的应用层协议

  • NFS: 网络文件系统
  • TFTP: 简单文件传输协议
  • DHCP: 动态主机配置协议
  • BOOTP: 启动协议(用于无盘设备启动)
  • DNS: 域名解析协议

当然, 也包括你自己写UDP程序时自定义的应用层协议;

说说DHCP,当你的电脑没连网的时候,没法上网,本质上是你的电脑没有IP,当连接上WiFi的时候(或者其他能连网方法),电脑会自动获取一个IP地址,这个IP是路由器给的,路由器内部署了DHCP服务,关了电脑之后IP会被自动回收。

再次谈论端口

再我前面写UDP和TCP服务器时,都要让服务端bind一个端口号,客户端也要绑定,但是不需要我们手动绑定,os会自动帮我们做。当本机拿到数据后向上交付时,要根据端口号交付给特定进程。

在这里插入图片描述

系统是如何快速找到端口号对应的进程的呢?
用哈希,可以理解为K值就是端口号,V值就是进程ID,要把有效载荷提供给应用层,就要找到进程的文件描述符,通过文件描述符把有效载荷拷贝到通信的文件中即可,找到文件描述符就先找到进程PCB就行,就这样通过PID找PCB,然后通过PCB找文件描述符。

五元组

在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信。

源IP和源端口号标定发送方的唯一进程。
目的IP和目的端口号标定接收方唯一进程。
协议号可以理解为标定传输层用的是哪一个协议,通常就是TCP或UDP。

这样的一个五元组就可以标定一个通信:
在这里插入图片描述

端口号范围划分

端口号是一个16位的二进制数,所以取值范围为0~65535。

0 - 1023: 知名端口号, HTTP, FTP, SSH等这些广为使用的应用层协议, 他们的端口号都是固定的.
就像是110就是警察,120就是急救,119就是火警一样。

有些服务器是非常常用的, 为了使用方便, 人们约定一些常用的服务器, 都是用以下这些固定的端口号:

  • ssh服务器, 使用22端口
    ftp服务器, 使用21端口
    telnet服务器, 使用23端口
    http服务器, 使用80端口
    https服务器, 使用443端口

/etc/services里面存放了常见端口号。
在这里插入图片描述

不要随意绑定0 ~ 1023的端口号。

1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的。我们自己也能选择其中的进行绑定。像我前面我在搞服务器的时候端口号用的基本上都是8080。

netstat

netstat是一个用来查看网络状态的重要工具.
语法:netstat [选项]
功能:查看网络状态
常用选项:

  • n 拒绝显示别名,能显示数字的全部转化成数字
  • l 仅列出有在 Listen (监听) 的服務状态
  • p 显示建立相关链接的程序名
  • t (tcp)仅显示tcp相关选项
  • u (udp)仅显示udp相关选项
  • a (all)显示所有选项,默认不显示LISTEN相关

在这里插入图片描述
这里查看的时候带的选项是natp。

n就是能显示成数字的就显示成数字,看第二行的sshd,如果我这里去掉n:
在这里插入图片描述
就变成了ssh,上面将协议固定端口的时候也说了,ssh的端口就是22。

a就是把状态为listen的也显示,我去掉a之后:
在这里插入图片描述

t就是显示tcp的服务,t换成u就是显示udp的服务:
在这里插入图片描述

p就是显示进程和其PID,也就是最后面的字段,去掉:
在这里插入图片描述

这里udp在接收服务的时候不会进行listen,至于什么原因我前面的博客中有,代码写过就知道了。

再看回来前面的这张图:
在这里插入图片描述

来看看sshd进程:
在这里插入图片描述

这个进程是一个守护进程(前面博客讲过,不懂点链接:【网络】用代码讲解协议 + 序列化和反序列化 + 守护进程 + jsoncpp),大部分以d结尾的进程一般都是守护进程(d就是daemon),三个ID相同,父进程是1os。

我这里用的是云服务器,登录的时候sshd会在终端为我开一个bash进程,并让我输入指令,输入后就将字符串发送给远在异地(北京、广东等)的服务器执行,并将执行后的结果返回。

xargs

这是一个命令行上的东西,可以将标准输入的内容转为命令行参数。

比如说我用pidof来获取一个进程的pid,然后用管道 + args交给kill命令,就可以关掉这个进程。
在这里插入图片描述

kill命令想使用的话必须得是命令行参数来搞,管道传输的数据是通过文件(标准输入)来实现的,没法直接给成命令行参数:
在这里插入图片描述
这里管道会将pidof的结果转成标准输入送给kill -9,但是kill -9执行的时候是将各个字段通过命令行参数来交给进程的,标准输入和命令行参数没有啥关系,无法直接执行kill命令,但是xargs会将标准输入的转成命令行参数,这样就可以传给进程执行了。

再比如说ls | xargs touch可以更新所有文件的ACM时间,改成最新的时间:
在这里插入图片描述

UDP比较简单,没有什么好讲的,你只要能写出我前面简易UDP服务器,懂本篇所讲的UDP报头就行。

到此结束。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/115240.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

技术文档工具『Writerside』抢鲜体验

前言 2023 年 10 月 16 日,JetBrains 宣布以早期访问状态推出 Writerside,基于 IntelliJ 平台的 JetBrains IDE,开发人员可使用它编写、构建、测试和发布技术文档,可以作为 JetBrains IDE 中的插件使用,也可以作为独立…

高防CDN的发展趋势

随着互联网的迅速发展,网站和在线服务的安全性变得至关重要。网络攻击如DDoS攻击和恶意流量正在增加,因此高防CDN(高防御内容分发网络)成为网络安全的重要组成部分。本文将探讨高防CDN未来的发展趋势,并比较其与传统CD…

laravel队列

laravel redis队列 1、创建job队列任务 php artisan make:job StoreUser执行上述命令后&#xff0c;会生成app/Jobs/StoreUser.php文件&#xff0c;编辑文件内容如下&#xff1a; <?phpnamespace App\Jobs;use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queu…

leetcode:231. 2 的幂(位运算)

一、题目&#xff1a; 函数原型&#xff1a;bool isPowerOfTwo(int n) 二、思路&#xff1a; 根据题意&#xff0c;要判断一个数是否为2的幂。如果一个数是2的幂&#xff0c;那么该数的二进制表示中只有一个1。所以只需要将该数的二进制表示中的最低位1移除&#xff0c;判断剩下…

三十七、【进阶】SQL的explain

1、explain 2、基础使用 在使用explain关键字时&#xff0c;只需要在所执行语句前加上explain即可 mysql> explain select * from stu where id3; ---------------------------------------------------------------------------------------------------------- | id | s…

2023网络安全工程师面试题汇总(附答案)

一、面试开场白 一般首先是一段例行的开场自&#xff08;说&#xff09;我&#xff08;学&#xff09;介&#xff08;逗&#xff09;绍&#xff08;唱&#xff09;&#xff0c;在这里我直接给你个万能公式&#xff1a; 1、在xx安全论坛投稿过xx篇文章&#xff0c;获得xx元稿费…

中文编程开发语言工具构件说明:屏幕截取构件的编程操作

屏幕截取 用于截取指定区域的图像。 图 标&#xff1a; 构件类型&#xff1a;不可视 重要属性 l 截取类型 枚举型&#xff0c;设置在截取屏幕时的截取类型。包括&#xff1a;全屏幕、指定区域、活动窗口三种。当全屏幕截取时相当于执行了硬拷屏&#xff08;PrintScre…

HVV(护网)蓝队视角的技战法分析

一、背景 1.HVV行动简介 HVV行动是国家应对网络安全问题所做的重要布局之一。从2016年开始&#xff0c;随着我国对网络安全的重视&#xff0c;演习规模不断扩大&#xff0c;越来越多的单位都加入到HVV行动中&#xff0c;网络安全对抗演练越来越贴近实际情况&#xff0c;各机构…

php 数组基础/练习

数组 练习在最后 数组概述 概述与定义 数组中存储键值对 数组实际上是一个有序映射 key-value&#xff0c;可将其当成真正的数组、列表&#xff08;向量&#xff09;、散列表、字典、集合、栈、队列等 数组中的元素可以是任意类型的数据对象&#xff08;可以嵌套数组&#…

英语什么时候加s和es

名词变复数一般情况下加s&#xff0c;以s,x,ch,sh结尾加es。一个名词如果表示一个或一样东西&#xff0c;它取单数形式&#xff0c;如果表示两个或更多的这类东西&#xff0c;则需要用名词复数形式。 1 以s,x,sh,ch结尾的词&#xff0c;加es。 2 以辅音字母&#xff08;除a/e/…

CNN系列

文章目录 R-CNN&#xff08;2014&#xff09;Conclusion SPP-net&#xff08;2015&#xff09; R-CNN&#xff08;2014&#xff09; 哈哈 创新&#xff1a; (1)人们可以将高容量卷积神经网络(cnn)应用于自下而上的区域建议&#xff0c;以定位和分割对象; (2)当标记训练数据稀缺…

python爬虫语法

注释 单行注释 # 多行注释 ‘’’注释内容’’’ 变量类型 和java不同不需要定义数据类型 变量名变量值 Numbers&#xff08;数字&#xff09;&#xff1a;int&#xff08;有符号整型&#xff09;、long&#xff08;长整型[也可以代表八进制和16进制]&#xff09;、float&am…

动画系统的前世今生(一)

掐指一算&#xff0c;五年没更新过我的CSDN账号啦&#xff0c;方向也从人工智能变成了计算机图形学&#xff0c;当然也依旧会关注AI的发展&#xff0c;之前在知乎上写了一些文章[传送门]&#xff0c;后续也会逐渐同步到CSDN上&#xff5e; 这个系列将包含五篇文章&#xff0c;内…

JVM 基础篇:类加载器

一.了解JVM 1.1什么是JVM JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;是一个虚构出来的计算机&#xff0c;是通过在实际的计算机上仿真模拟计算机功能来实现的&#xff0c;JVM屏蔽了与具体操作系统平台相关的信息&#xff0c;Java程序只需…

从Excel到智能化:智能报表的演进与未来发展趋势

摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 报表的迭代历程 报表工具的诞生与计算机技术的出现和信息技术的进步密不可分。下图是报…

2017年高热度编程语言简介

世上语言千千万&#xff0c;我却独爱这一种!”这句话用来形容程序员和编程语言之间的爱恨情仇实在是再精准不过了。根据GitHub 2016年的开源报告&#xff0c;其上所有开源项目共包含了316种编程语言&#xff0c;这是一个什么概念呢?举个例子来说&#xff0c;世界上共有226个国…

粤嵌实训医疗项目day02(Vue + SpringBoot)

目录 一、创建vue项目并运行 二、vue-cli中的路由使用 三、element-ui框架、实现页面布局以及vue-路由 四、前端登录页面 五、user登录后端接口完善【后端】 六、user登录前端-请求工具-请求发起【前端】 七、请求的跨域-访问策略 八、完善项目的页面布局、导航菜单以及…

“香蕉大王”的转型升级,能否扩大市场份额?

佳农食品控股 ( 集团 ) 股份有限公司,于2023年10月11日同海通证券签署上市辅导协议&#xff0c;计划登陆上交所主板。据了解这已经不是佳农食品第一次IPO了&#xff0c;2019 年&#xff0c;佳农集团曾向上交所递交过招股说明书&#xff0c;当时的招股书披露&#xff0c;佳农集团…

python爬虫入门(一)web基础

HTTP基本要点 HTTP请求&#xff0c;由客户端向服务端发出&#xff0c;可以分为 4 部分内容&#xff1a;请求方法&#xff08;Request Method&#xff09;、请求的网址&#xff08;Request URL&#xff09;、请求头&#xff08;Request Headers&#xff09;、请求体&#xff08…

如何破解压缩包密码,CTF压缩包处理

I. 引言 压缩包我们经常接触&#xff0c;用于对文件进行压缩存储/传输。压缩包处理在CTF比赛中是非常重要的一块&#xff0c;因为压缩包中可能包含重要信息&#xff1a;许多CTF题目会将关键信息隐藏在压缩包中&#xff0c;参赛者需要解压并查看其中的内容才能获取有用的线索。…