你ping一下,服务器累成狗--第二篇

你ping一下,服务器累成狗-目录篇文章浏览阅读1.7k次,点赞65次,收藏20次。我们的电脑怎么干活的https://blog.csdn.net/u010187815/article/details/135796967

你ping一下,服务器累成狗--第一篇文章浏览阅读62次,点赞6次,收藏2次。ping的时候都干了什么https://blog.csdn.net/u010187815/article/details/135943085

简简单单

简简单单的一个ping动作,中间涉及的内容几乎包含了计算机领域里面所有的基础内容,复杂而精妙。

这篇文章一次肯定写不完,最后写完了肯定也不可能包含所有的内容。我对其中的一些内容也早就忘的干净,不过既然写了,就认真写,能写多少写多少,能写多细写多细,并且尽量表达的通俗易懂一点,有哪里不对的地方,别打我,跟我说,我会改。

先上一个大致的流程图,后面也会按照这图里的四个点分开讲

892237255fff4dc7b3352a024be7d77f.png从用户程序到内核执行

概述

执行ping命令时,操作系统会创建一个进程,分配一个PID,分配相应的资源,比如内存空间,CPU时间片,文件描述符,网络端口等,这个和执行普通的应用程序没有什么区别。

同样ping命令和普通的应用程序也都需要通过一些系统调用来让内核帮他做一些事情,应为进程正常是在用户空间运行,在用户空间里面,应用程序可以使用的系统资源和系统功能是非常受限的。

进程通过系统调用可以接触到操作系统底层的很多能力,比如:

  1. 文件操作:open、close、read、write、lseek、stat、fstat、mkdir、rmdir、unlink等。
  2. 进程管理:fork、exec、exit、wait、waitpid、getpid、getppid、kill、signal等。
  3. 进程间通信:pipe、shmget、shmat、shmdt、semget、semop、msgget、msgsnd、msgrcv等。
  4. 网络通信:socket、bind、listen、accept、connect、send、recv、select、poll等。
  5. 内存管理:brk、mmap、munmap、mprotect、malloc、free等。
  6. 时间和日期:time、gettimeofday、clock_gettime、strftime等。
  7. 设备和I/O操作:ioctl、read、write、select等。
  8. 信号处理:signal、sigaction、kill、sigprocmask等。
  9. 用户和组管理:getuid、getgid、geteuid、getegid、setuid、setgid等。

可以说进程的很多核心的能力都需要通过系统调用来“陷入内核”,让内核帮忙执行。

分配进程描述符--struct task_struct

  1. volatile long state:进程状态,表示进程当前的运行状态,例如运行、等待、睡眠等。
  2. void *stack:进程的内核栈指针。
  3. struct thread_info *thread_info:指向线程信息的指针。
  4. struct task_struct *parent:指向父进程的task_struct结构。
  5. struct list_head children:指向子进程链表的头结点。
  6. struct list_head sibling:指向同一父进程的兄弟进程链表。
  7. struct pid_struct *pid:进程ID相关的结构体指针。
  8. struct cred *real_cred:指向实际用户凭证的指针。
  9. struct cred *cred:指向当前任务用户凭证的指针。
  10. struct file *files:文件描述符表的头指针。
  11. struct signal_struct *signal:进程的信号处理相关信息。
  12. struct mm_struct *mm:指向进程的内存管理结构。
  13. struct cpu_struct cpu:表示进程所在CPU的信息。
  14. struct nsproxy *nsproxy:用于多个命名空间的进程间共享的命名空间信息。
  15. struct timer_list real_timer:进程的实时定时器。
  16. struct timer_list virt_timer:进程的虚拟定时器。
  17. struct kernel_vm86_regs vm86:VM86模式的寄存器信息。
  18. unsigned long flags:进程的标志位。
  19. char comm[TASK_COMM_LEN]:进程的名称。
  20. struct io_context *io_context:用于异步I/O的上下文信息。

内核会把所有的进程描述符放到一个叫任务队列的双向循环链表中。上述中第七项PID是进程的唯一标识,其类型是short类型,所以默认最大为32768,有一些特定的版本中也会用large PID(int类型)来支持4294967295个进程。

创建后的进程经过短暂的创建状态后(会阻止内核将时间片分给它),就会进入Task_Running状态(包含待运行和正在运行)。需要注意的是,如果应用程序因为执行时间片到期了,被内核切出去了,那么这时候他的状态也是Task_Running。如果进程为了等待一些事件就会进入Task_Interruptible或Task_Uninterruptible状态。

进程的创建和终结时释放资源的过程这里就不阐述了,各位可以网上自己查查。

进程调度

从进程进入Task_Running状态后,就可以接受调度程序为他分配的时间片了,让它可以真正的运行起来。至于怎么调度,完全取决于调度程序的实现。有一点需要区分于硬件硬件的处理,上一篇中我们讲到中断处理程序自身一旦执行是不可中断的。而在进程调度中,会按照优先级和分配的时间片去中断当前的在CPU执行的进程。这个时候就会有进程上下文的概念。先来看看两种调度算法

调度算法

O(1)调度算法:
核心思想:

将进程的调度决策与其优先级相关联,每个进程都被分配一个动态优先级,该优先级的范围通常是0-139,数值越低代表优先级越高。进程的优先级可以在运行时根据其运行情况进行调整。

O(1)调度算法中,进程的状态被分为两个就绪队列:活动队列(Active Queue)和过期队列(Expired Queue)。活动队列中包含了当前正在运行的进程,而过期队列中包含了已经运行一段时间的进程。

算法的主要步骤如下:
  1. 初始化活动队列和过期队列,并设置时间片(time slice)。
  2. 从活动队列中选择一个进程来运行。这个选择是基于进程的优先级来进行的,优先级越高的进程被选择的概率越大。
  3. 当一个进程的时间片用完后,它将被移动到过期队列,同时分配一个新的时间片。
  4. 在过期队列中选择一个进程,并将其移到活动队列中运行。
  5. 当活动队列为空时,活动队列和过期队列交换位置,过期队列变为活动队列,继续执行步骤2-4。
  6. 如果没有可运行的进程,调度器将选择一个最高优先级的空闲进程来执行。
O(1)调度算法的主要优点

其调度决策具有常数时间复杂度,不会随着进程数量的增加而变慢。它还可以根据系统负载动态地调整进程的优先级,以提高系统的整体性能。

O(1)调度算法的主要缺点

由于其调度决策是基于优先级而不是实际执行时间的,可能存在某些进程一直处于低优先级导致无法运行的情况。此外,O(1)调度算法不能很好地适应多核系统和对对称多处理机(SMP)的需求。

CFS调度算法
核心思想:

基于"虚拟运行时间"来进行调度决策。每个进程被分配一个虚拟运行时间片(virtual runtime),它表示进程在CPU上运行的预期时间。系统根据这个虚拟运行时间来决定下一个要运行的进程,以保证进程获得公平的CPU时间。

CFS调度算法的主要步骤如下:
  1. 初始化CFS调度器,并设置根任务(root task)的虚拟运行时间片。
  2. 当有进程需要运行时,CFS调度器选择根任务中虚拟运行时间片最低的子任务(即虚拟运行时间最小的进程)作为下一个要运行的进程。
  3. 选定进程后,CFS调度器将更新进程的虚拟运行时间,并分配给它一个时间片(也称为时间配额),该时间片与进程的优先级成比例。
  4. 运行过程中,CFS调度器会根据进程的运行时间和虚拟运行时间的差异,动态地调整进程的虚拟运行时间和时间片的长度。
  5. 当一个进程的时间片用完后,CFS调度器将重新选择一个虚拟运行时间最低的进程作为下一个要运行的进程,并分配时间片给它。
  6. 如果没有可运行的进程,CFS调度器将选择一个最高优先级的空闲进程来执行。
CFS调度算法的主要优点:

能够提供公平的CPU资源分配,确保每个进程获得相等的CPU时间。它通过虚拟运行时间和时间片的动态调整,可以适应不同进程的运行需求,并提供比较低的延迟和响应时间。

CFS调度算法也支持实时进程的调度,通过提供一个确切的实时进程时间的机制,以确保实时进程能够在特定时间内获得CPU时间。

进程的优先级怎么定

知道了调度算法,我们就需要知道调度算法是根据什么来给应用程序分配时间片的,无论是优先级的绝对值,相对值或者百分比。

进程定义优先级分两种类型,

一种是nice值,这种值使用在普通进程上,范围是-20到+19。值越大表示优先级越低。

另一种是实时优先级,范围值是0到99。值越大表示优先级越高。

进程上下文的由来

当进程A的某次的时间片用完主动释放时或者被其他更高优先级的进程B,C等强行抢占或者需要调用系统能力的时候,就需要将当前的进程的信息上下文信息,并加载下一个进程的上下文信息。主要是用来恢复进程的运行。

其他两种的就不说明了,主要来说说什么是系统调用

ping里面的系统调用

执行ping命令时,涉及了以下系统调用:

  1. socket:创建一个套接字,用于与目标主机建立网络连接。
  2. sendto:将ping请求发送给目标主机的IP地址。
  3. recvfrom:接收目标主机返回的ping响应。
  4. gettimeofday:获取当前时间,用于计算ping命令的延迟。
  5. setsockopt:设置套接字选项,如超时时间等。
  6. close:关闭与目标主机的连接。

所谓的系统调用就是操作系统中有一些能力是不能被用户空间直接访问的,这时候就需要通过系统调用来让内核帮忙执行。上一文中我们讲了硬件是通过向内核注册的中断处理程序来响应的,而应用程序则是通过系统调用让内核代替用户程序去执行动作。

一般来说,应用程序通过触发一个内核级别的特殊的异常来触发某个系统调用,这个异常会有指定的异常处理程序一般只system_call。

ICMP报文的组装

网络协议层间的处理和传递:ping命令使用的是ICMP协议,在网络协议栈中,操作系统会将ping命令封装为一个ICMP数据报,并通过网络接口发送出去。在传输过程中,操作系统会根据IP地址和MAC地址进行路由选择,并在每一层协议中添加相应的头部信息。

在数据链路层:在以太网、Wi-Fi等物理网络接口层,ICMP报文作为数据负载被封装在一个数据帧中。数据帧的头部包含了目标MAC地址和源MAC地址等信息。

在网络层:ICMP报文被封装在IP数据报中,IP数据报的头部包含了目标IP地址和源IP地址等信息。此外,IP数据报的协议字段(Protocol)标识为ICMP,以指示IP层将数据报交付给上层的ICMP协议进行处理。

在传输层:对于ICMP报文,它并没有在传输层上添加额外的头部信息。这是因为ICMP协议是网络层的一部分,直接封装在IP数据报中,在传输层上没有进行额外的封装。

简化的报文如下

Ethernet II(以太网帧)

  • 目标MAC地址:01:23:45:67:89:ab
  • 源MAC地址:de:ad:be:ef:12:34
  • 类型:IPv4 (0x0800)

IPv4(IP数据报)

  • 版本:IPv4
  • 首部长度:20字节
  • 总长度:84字节
  • 标识:0x1234
  • 标志(Flags):0x00
  • 分片偏移:0
  • 生存时间(TTL):64
  • 协议:ICMP (1)
  • 源IP地址:192.168.0.1
  • 目标IP地址:8.8.8.8

ICMP(ICMP Echo Request报文)

  • 类型:Echo Request (8)
  • 代码:0
  • 校验和:0x1234
  • 标识符(Identifier):0x5678
  • 序列号(Sequence Number):0x0001
  • 数据(Payload):具体的ping命令中提供的数据部分(通常为一段字节序列)

DNS解析-替你周游了世界

如果ping命令指定了目标主机的域名,而不是直接的IP地址,操作系统会进行DNS解析,将目标主机域名转换为对应的IP地址。DNS解析过程涉及应用程序向操作系统发起系统调用(如getaddrinfo),操作系统向DNS服务器发送查询请求,接收并解析DNS响应,最终将解析到的IP地址返回给应用程序。

  1. 检查目标主机是否为IP地址。如果目标是一个IP地址,跳过DNS解析步骤。

  2. 获取目标主机的域名,例如www.baidu.com。

  3. 由于ping命令运行在操作系统中,它需要发起系统调用来执行DNS解析。在类Unix系统上,通常使用getaddrinfo()系统调用进行DNS解析。该系统调用将目标主机的域名作为输入参数,并返回一个或多个与该域名对应的IP地址。

  4. 当操作系统或应用程序发起DNS解析请求时,解析器会首先检查本地缓存,看是否已经缓存了与请求域名对应的IP地址。如果找到了匹配的缓存项,解析器会直接使用缓存中的IP地址,避免进行完整的DNS解析过程。

  5. 系统调用将查询发送给本地DNS解析器,这个解析器通常由本地网络服务提供商(ISP)或者配置的本地DNS服务器提供。解析器将查询转发给根DNS服务器。

  6. 根DNS服务器负责管理顶级域名服务器(如.com、.net、.org等)。它可能不知道目标主机的确切IP地址,但它可以指示解析器转到负责特定顶级域名的权威DNS服务器。

  7. 解析器将查询转发给负责.com顶级域名的权威DNS服务器。

  8. 权威DNS服务器具有目标主机的区域文件,其中包含与目标主机相关的DNS记录。它会查找并返回与目标主机匹配的A记录或AAAA记录(IPv6地址)。

  9. 解析器接收到响应,其中包含目标主机的IP地址。

  10. 解析器将IP地址返回给ping程序。

  11. ping程序将使用获取的IP地址创建ICMP Echo Request报文,并开始向目标主机发送ping请求。

发送ICMP请求

在网络层中,操作系统会根据目标IP地址创建一个ICMP请求数据包,并在传输层中使用IP协议封装,然后通过网卡发送出去。

  1. 应用程序调用发送数据的系统调用(例如,send())将数据写入应用程序缓冲区。

  2. 操作系统内核会定期检查应用程序缓冲区中是否有数据需要发送。这可以通过轮询或阻塞等方式完成。

  3. 内核从应用程序缓冲区中获取数据,并将其复制到内核的网络数据缓冲区。

  4. 内核将数据分割成适当的大小(根据MTU和网络协议的要求),然后为每个数据包分配一个或多个网络缓冲区。

  5. 内核将数据包的相关信息(例如目的MAC地址、源MAC地址、目的IP地址、源IP地址、协议类型等)填充到网络数据包的头部中。

  6. 内核检查网络接口的状态,确保它处于活动状态,并将数据包传递给网络设备驱动程序。

  7. 网络设备驱动程序将数据包发送到相应的网卡(NIC)。

  8. 网卡芯片将数据包转换成电信号,并通过物理介质(例如以太网电缆)发送出去。

  9. 数据包到达目标主机后,接收端的网卡接收到数据包。

  10. 目标主机的操作系统内核接收到数据包,并将其传递给相应的网络协议栈进行处理。

拆包和粘包 

由于ICMP报文比较简单,通常只包含一个报文头部和可选的数据字段。因此,ICMP报文很少会出现拆包和粘包的问题。每个ICMP报文都以独立的形式发送和接收,不会与其他报文粘在一起。

拆包和粘包是在传输层的协议栈中处理的,主要由传输层协议(例如TCP或UDP)负责。

拆包和粘包指的是在数据传输过程中,发送方将应用层数据切割成多个数据包进行发送,而接收方在接收数据时,可能会一次接收到多个数据包(粘包)或者只接收到部分数据包(拆包)的情况。

具体来说,在TCP连接中,发送方将应用层数据切分成适当的大小(根据MSS,最大报文段长度)的数据段,并在每个数据段的头部添加TCP头部信息,形成TCP数据包。接收方在接收数据时,会根据TCP头部的信息来将接收到的数据进行重组,还原为应用层数据。因此,在TCP连接中,拆包和粘包问题主要是由TCP协议负责处理的。

在UDP连接中,并没有像TCP一样的连接维护和重组机制。发送方将应用层数据直接封装成UDP数据报,每个UDP数据报都有固定的大小。接收方在接收数据时,根据每个UDP数据报的边界进行接收和处理。由于UDP是面向无连接的传输协议,因此它没有像TCP那样的流量控制和拥塞控制机制,所以拆包和粘包问题在UDP中可能更加突出。

流量控制和拥塞控制机制

流量控制

流量控制是通过接收方通知发送方的方式来控制数据的传输速率,确保接收方能够及时处理接收到的数据,避免数据丢失或溢出。TCP使用滑动窗口机制来实现流量控制。发送方根据接收方给出的窗口大小来调整发送数据的速率,窗口大小反映了接收方当前能够接收的数据量。如果窗口大小变小,发送方需要降低发送速率;如果窗口大小增大,发送方可以增加发送速率。通过不断调整窗口大小,TCP可以实现发送和接收之间的匹配,从而实现流量控制。

拥塞控制

拥塞控制是为了避免网络出现拥塞而引发的性能下降和数据丢失。拥塞发生时,网络中的资源(带宽、缓存等)已经无法满足连接的需求,导致数据包丢失、延迟增加等问题。TCP通过一系列的算法来实现拥塞控制,其中包括拥塞窗口(cwnd)和慢启动、拥塞避免、快速重传、快速恢复等机制。

  • 慢启动:初始发送速率较低,随着时间的增加指数级增加发送速率,以便逐步测试网络的负载能力。
  • 拥塞避免:在慢启动阶段和拥塞避免阶段,发送方将指数级增加拥塞窗口,但增加速率更慢,确保在发生拥塞之前能够按照网络的容量进行发送。
  • 快速重传和快速恢复:当发送方接收到三个重复的ACK时,表明有一个数据包已经丢失,发送方立即重传丢失的数据包并进行快速恢复,而不是等到超时后再进行重传,从而减少网络拥塞的程度。

 

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

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

相关文章

C#用正则表达式验证格式:电话号码、密码、邮编、手机号码、身份证、指定的小数点后位数、有效月

正则表达式在程序设计中有着重要的位置,经常被用于处理字符串信息。 用Regex类的IsMatch方法,使用正则表达式可以验证电话号码是否合法。 一、涉及到的知识点 Regex类的IsMatch方法用于指示正则表达式使用pattern参数中指定的正则表达式是否在输入字符串…

IntersectionObserver、MutationObserver应用,监听项目中指定属性数据,点击或模块显示时

当项目中,需要获取某个页面上、某个标签上、有指定自定义属性时,需要在点击该元素时进行公共逻辑处理,或该元素在显示的时候进行逻辑处理,这时可以定义一个公共的方法,在每个页面引用,并写入数据即可 &…

OSPF的优化

一:OSPF的优化:---lsa的优化 1、汇总 --- 减少骨干区域LSA更新量 2、特殊区域 --- 减少非骨干区域LSA更新量 二:汇总 1、区域汇总:OSPF的汇总被称为区域汇总 域间路由汇总---针对OSPF区域之间的路由进行汇总,针对…

【机器学习300问】21、什么是激活函数?常见激活函数都有哪些?

在我写的上一篇文章中介绍了感知机(单个神经元)的构成,其中就谈到了神经元会计算传送过来的信号的总和,只有当这个总和超过了某个界限值时,才会输出值。这也称为“神经元被激活”。如果想对神经网络是什么有更多了解的…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之DataPanel组件

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之DataPanel组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、DataPanel组件 数据面板组件,用于将多个数据占比情况使用占比图进…

集成学习之Boosting方法系列_XGboost

文章目录 【文章系列】【前言】【算法简介】【正文】(一)XGBoost前身:梯度提升树(二)XGBoost的特点(三)XGBoost实际操作1. 前期准备(1)数据格式(2&#xff09…

小程序定制开发:解析定制化移动应用的未来

引言 在当今数字化时代,移动应用已经成为人们生活不可或缺的一部分。随着智能手机的普及,移动应用的需求呈现出爆发式增长,企业们也纷纷投身于这场数字化浪潮。然而,众多企业在竞争激烈的市场中,如何突显个性、提高用…

使用Eclipse搞Android项目报错

相信现在都没什么人还会用Eclipse来开发的了。 不过安装完后,打开Eclipse会提示我的Jdk版本不符合 --------------------------- Incompatible JVM --------------------------- Version 1.8.0_391 of the JVM is not suitable for this product. Version: 17 or g…

python之poetry模块,项目管理

一、简介 Poetry 是一个用于管理 Python 项目依赖关系和构建工具的工具。它提供了一个简单的命令行界面,可以帮助您创建、管理和发布 Python 项目,使用方法:command [options] [arguments] 官网:https://python-poetry.org/docs/…

详解SpringCloud微服务技术栈:深入ElasticSearch(1)——数据聚合

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习 🌌上期文章:详解SpringCloud微服务技术栈:ElasticSearch实战(旅游类项目) 📚订阅专栏&#x…

软件设计不是CRUD(11):低耦合模块设计理论——业务抽象:规划模块分层

上一篇文章《软件设计不是CRUD(10):低耦合模块设计理论——业务抽象:从需求中提取业务维度》本专题详细讲解了业务抽象的一个重要步骤:提取业务维度。本篇文章内容主要讲解在提取业务维度后,如何对应用程序中初步划分的各个功能模块进行分层规划。 1、为什么要进行模块分…

【lesson2】定长内存池的实现

文章目录 介绍定长内存池的设计定长内存池的实现需要成员变量需要的成员函数定长内存池结构定长内存池Delete(释放空间)的实现定长内存池New(申请空间)的实现 定长内存池的实现完整版 介绍 作为程序员(C/C)我们知道申请内存使用的…

Zookeeper实现分布式队列

目录 Zookeeper分布式队列 普通方式实现 设计思路 具体实现 使用Curator实现 具体实现 注意事项 Zookeeper分布式队列 常见的消息队列有:RabbitMQ,RocketMQ,Kafka等。Zookeeper作为一个分布式的小文件管理系统,同样能实现简单的队列功…

【python】图形化开发pyqt6基本写法模板与基础控件属性方法整理

pyqt6的简介 首先呢Python有许多可以编写图形化界面的库,我们通常跟着教程的话最初会接触的tkinter,但是学习中会发现编写的图形化跟我们平常接触的软件有很大区别(简单来说就是丑)。 pyqt则是第三方库,在Python中算…

ETL怎么实现文件处理

在现代企业及各类组织的日常运作中,数据作为一种关键的信息资源,其管理和分析能力直接影响到决策效率与准确性。文件作为数据的主要载体,承载着从运营报告、客户记录、交易明细等各种类型的数据信息。这些海量且多样的文件数据在未经处理的情…

flask_django基于python的城市轨道交通公交线路查询系统vue

同时,随着信息社会的快速发展,城市轨道交通线路查询系统面临着越来越多的信息,因此很难获得他们对高效信息的需求,如何使用方便快捷的方式使查询者在广阔的海洋信息中查询,存储,管理和共享信息方面有效&…

C语言菜鸟入门·运算符(算数运算符,关系运算符,逻辑运算符,位运算符,赋值运算符,三目运算符)详细介绍

目录 ​编辑 1. 算术运算符 2. 关系运算符 3. 逻辑运算符 4. 位运算符 5. 赋值运算符 6. 杂项运算符 ↦ sizeof & 三元 6.1 sizeof() 6.2 &取地址运算符 6.3 * 6.4 三目运算符 7. 运算符优先级 运算符是一种告诉编译器执行…

ElementUI组件:Link 文字链接

Link 文字链接 点击下载learnelementuispringboot项目源码 效果图 el-link.vue页面效果图 项目里el-link.vue文件代码 <script> export default {name: el_link }</script> <!--https://element.eleme.cn/#/zh-CN/component/link --> <template>&l…

嵌入式学习第十四天

1.结构体&#xff08;2&#xff09;: &#xff08;1&#xff09;结构体类型定义 &#xff08;2&#xff09;结构体变量的定义 &#xff08;3&#xff09;结构体元素的访问 &#xff08;4&#xff09;结构体的存储: 内存对齐: char 按照1字节对齐 …

C# OpenCvSharp DNN Gaze Estimation 视线估计

目录 介绍 效果 模型信息 项目 代码 frmMain.cs GazeEstimation.cs 下载 C# OpenCvSharp DNN Gaze Estimation 介绍 训练源码地址&#xff1a;https://github.com/deepinsight/insightface/tree/master/reconstruction/gaze 效果 模型信息 Inputs ----------------…