当前位置:   article > 正文

JavaEE(2)(进程的管理 【进程标识符PID、内存指针、文件描述符表、进程的调度——<状态,优先级,上下文,记账信息,操作系统调度器和调度算法 >、虚拟地址空间、进程之间相互协作和交互数据】)_java pid 文件 维护

java pid 文件 维护

接上次博客:JavaEE初阶(1)(冯诺依曼体系、CPU、CPU基本原理、如何衡量CPU的好坏?指令、操作系统、操作系统“内核”)_di-Dora的博客-CSDN博客

目录

进程/任务(Process/Task)

进程的管理 

1、PID(进程标识符): 

2、内存指针:

3、文件描述符表

进程的调度

进程的状态:

进程的优先级:

进程的上下文:

进程的记账信息:

操作系统调度器和调度算法 

虚拟地址空间

进程之间相互协作和交互数据


进程/任务(Process/Task)

每个应用程序运行于现代操作系统之上时,操作系统会提供一种抽象,好像系统上只有这个程序在运 行,所有的硬件资源都被这个程序在使用。进程是操作系统对一个正在运行的程序的一种抽象,换言之,可以把进程看做程序的一次运行过程; 同时,在操作系统内部,进程又是操作系统进行资源分配的基本单位。

简单来说,进程就是指一个已经运行起来的程序:

对于Windows这个程序来说,一开机就有百八十个进程,有的是系统自动创建的,有的是我们手动创建的。 

而没有运行的就不叫进程,只是应用程序。

在图里,你可能会注意到后面这个部分:

每个进程想要执行,就都需要消耗一定的系统资源(硬件资源)。这个部分列出了每个进程消耗的系统资源的多少。

由此可知,每个进程都是操作系统中系统资源分配的基本单位。操作系统通过进程来管理和分配计算机的各种资源,包括:

  1. 内存:每个进程都有自己的独立地址空间,操作系统负责分配和管理内存,以确保不同进程之间不会相互干扰或越界访问。

  2. CPU时间:操作系统通过调度算法分配CPU时间片给不同的进程,使它们能够轮流执行,从而实现多任务处理。

  3. 文件和I/O资源:每个进程可以打开、读取和写入文件,操作系统管理文件系统和I/O设备,以便进程能够访问和操作文件和外部设备。

  4. 网络连接:对于网络应用程序,操作系统负责管理网络连接和数据传输,确保进程能够进行网络通信。

  5. 设备驱动程序:操作系统提供设备驱动程序,允许进程与硬件设备进行交互,如打印机、键盘、鼠标等。

  6. 进程间通信:操作系统提供进程间通信(IPC)机制,使不同进程能够共享数据和进行通信。

  7. 安全性和权限控制:操作系统确保每个进程只能访问其被授权的资源,以维护系统的安全性。

接下来,我们详细了解一下进程在系统中如何进行管理的。

进程的管理 

管理涉及到两个角度:

1、描述:使用类/结构体,把被管理的一个对象的各个属性都表示出来;

2、组织:使用数据结构,把这些表示出来的对象串联起来,为了方便后续的增删改查。

系统中专门有一个结构体(操作系统内核是由C/C++写的)描述进程的属性,这个结构体叫做“进程控制块”(Process Control Block , PCB)。

PCB包含了进程的重要信息,如进程ID、状态、寄存器内容、程序计数器、内存分配情况、打开的文件列表等。PCB的目的是将进程的关键属性可视化和管理化,以便操作系统能够有效地控制和维护进程。

我们使用PCB描述进程的属性,一个进程就可以使用一个或者多个PCB来表示。

系统中会使用类似于双向链表这样的数据结构来组织多个PCB。

  • 创建新的进程就是创建PCB并且把PCB插入到链表中。
  • 销毁进程就是把PCB从链表上删除并释放。
  • 展示进程列表就相当于是遍历链表的每个节点

要想更明确的认识进程的详细特性,我们还需要讨论一下PCB里面的属性,

PCB是一个非常庞大的结构体,因为它需要包含很多属性和信息,以便操作系统能够有效地管理和控制进程。(Linux这样的操作系统代码是开源的,你可以去翻一下源码,只不过它管PCB叫task_struct) 

我们来看看PCB的几个主要属性:

  1. 进程标识:包括唯一的进程ID和父进程ID等标识信息。

  2. 状态信息:表示进程的当前状态,如运行、就绪、等待等。

  3. 寄存器信息:保存进程的寄存器状态,以便在上下文切换时能够恢复进程的执行现场。

  4. 程序计数器:指向进程正在执行的指令的地址。

  5. 内存管理信息:包括进程的内存分配情况、页表等内存管理相关信息。

  6. 文件描述符表:维护进程打开的文件和文件描述符的列表。

  7. 资源占用信息:表示进程当前占用的资源,如CPU时间、内存、设备等。

  8. 优先级和调度信息:包括进程的优先级和调度参数,用于操作系统的进程调度。

  9. 进程控制信息:包括进程的父进程ID、子进程列表等。

  10. 进程状态信息:用于记录进程的运行时间、创建时间等状态相关信息。

我们重点了解一下其中比较核心的几个:

1、PID(进程标识符): 

PID(进程标识符)是一个唯一的数字,用于标识操作系统中每个正在运行的进程。每个进程在创建时都会被分配一个唯一的PID,这个PID在同一时刻不同进程之间是不同的(唯一性)。PID通常是一个整数,可以是正整数或非负整数。

PID的主要作用包括:

  1. 唯一标识:PID确保每个进程都具有不同的标识符,使操作系统能够准确地识别和区分各个进程。

  2. 进程管理:操作系统使用PID来管理进程,包括创建、销毁、调度和监视进程的状态。

  3. 进程通信:PID也用于进程间通信(IPC)机制,以便不同进程能够相互识别和通信。

  4. 资源分配:PID还可用于标识进程占用的资源和权限,以确保资源的合理分配和访问控制。

2、内存指针:

每个进程在运行的时候,都会分配一定的内存空间。这个内存空间通常称为进程的虚拟地址空间。进程的虚拟地址空间包括多个区域,每个区域具有不同的用途,用于存储不同类型的数据。以下是典型的进程虚拟地址空间中的一些重要区域和指针:

  1. 代码区(Text Segment)

    • 代码区存储了进程的可执行代码,通常是程序的二进制指令。这些指令被加载到内存中,供CPU执行。
    • 指令指针(Instruction Pointer,通常是程序计数器PC)指向当前要执行的指令。
  2. 数据区(Data Segment)

    • 数据区包括初始化的全局和静态变量。这些变量在程序运行时会被分配内存空间,用于存储数据。
    • 全局指针(Global Pointer)通常指向数据区中的数据。
  3. 堆区(Heap)

    • 堆区用于动态内存分配,程序可以在运行时请求分配和释放内存。常见的内存分配函数包括 malloc、free等。
    • 堆指针(Heap Pointer)用于跟踪堆区的内存分配情况。
  4. 栈区(Stack)

    • 栈区用于存储函数调用的上下文信息、局部变量以及函数的返回地址。每个函数调用都会在栈上创建一个新的栈帧。
    • 栈指针(Stack Pointer)指向当前栈帧的顶部,用于管理函数调用和局部变量的访问。
  5. 其他区域

    • 进程的虚拟地址空间还可以包括其他区域,如共享库区域、内存映射区域等,用于存储共享库代码、映射文件等。

进程的虚拟地址空间是由操作系统管理的,操作系统负责分配和管理进程的内存,确保不同进程之间的内存不会互相干扰。指针是用来访问这些不同区域的关键工具,如栈指针、堆指针、全局指针等。程序的执行过程中,这些指针会根据函数调用、内存分配和释放等操作而不断地移动和更新,以便正确地访问和管理内存。

C语言程序或其他可执行程序在运行时会经历以下过程:

  1. 加载可执行文件

    • 当用户双击可执行文件(.exe)时,操作系统会加载该文件的内容到内存中。
    • 这包括程序的二进制指令(代码区)和程序所需的静态数据(数据区)。
  2. 执行指令

    • CPU从代码区中读取指令,并按照指令的顺序执行程序的逻辑。
    • 指令指针(Instruction Pointer,通常是程序计数器PC)指向当前要执行的指令。
  3. 数据加载

    • 程序的静态数据(如全局变量和静态变量)存储在数据区中,并随着程序加载到内存中。
    • 数据区中的数据可供程序访问和修改。
  4. 动态内存分配

    • 程序可以在运行时使用动态内存分配函数(如 malloc)来请求额外的内存空间,这些内存空间位于堆区。
    • 堆区用于存储动态分配的数据,这些数据的生命周期由程序控制。
  5. 栈区管理

    • 栈区用于存储函数调用的上下文信息、局部变量和函数返回地址。
    • 每个函数调用都创建一个新的栈帧,用于存储该函数的参数和局部变量。
    • 栈区的内存分配和释放是自动管理的。
  6. 临时数据存储

    • 程序运行过程中可能会生成临时数据,这些数据通常存储在栈区或堆区中,具体取决于其生命周期和用途。
    • 栈区用于存储短暂的局部数据,而堆区用于存储动态分配的临时数据。

总之,可执行程序在运行时会将代码和静态数据加载到内存中,CPU会执行这些指令,而数据区用于存储程序的静态数据。程序还可以使用堆区和栈区来管理动态分配的数据和临时数据。这种内存管理机制允许程序在运行时有效地管理数据和执行逻辑。

综上,进程的虚拟地址空间包括多个区域,每个区域用于存储不同类型的数据。指针在进程的内存管理中起着关键作用,帮助程序访问和操作不同区域的数据。这种内存管理机制确保了进程的安全性和隔离性。

还有一句很重要的话一定要记住,内存指针描述了进程持有的“内存资源”是啥样的。

3、文件描述符表

文件描述符表是用来管理和跟踪进程与文件之间关系的一种数据结构,通常采用类似于顺序表的方式来组织,有很多元素和文件有关,也就对应着和硬盘有关。文件描述符表维护了进程当前打开的文件的信息,包括文件的类型、访问权限以及文件在文件系统中的位置等。

简单来说,一个进程也需要涉及到硬盘操作,就需要按照文件的方式来操作。当前进程关联了哪些文件?都能操作哪些文件?都是通过文件描述符表来确定。

通过文件描述符表,操作系统就可以有效地管理进程与文件之间的关联,使进程能够进行文件操作而无需关心文件的实际物理位置。这种机制允许多个进程同时访问文件系统,确保了数据的完整性和安全性。

因此,文件描述符表描述了进程持有的“硬盘资源”是啥样的

那么,进程持有的CPU资源如何体现?这就更加复杂了,涉及到“进程的调度”。

进程的调度

早期的操作系统是一个“单任务操作系统”,同一时刻只有一个进程能够运行,运行下一个程序,就会退出上一个,这个时候不需要考虑调度的问题。

但是,当时的电脑都是能支持多个任务了,这是怎么做到的?

一个进程要执行,就需要CPU来执行上面的指令。而早期的电脑还是单核CPU,也就是说它同一时刻只能执行一个进程的指令。

在这个背景下我们又怎么实现“多个任务”同时进行呢?

这就涉及到一个词——“分时复用”,用两个字来描述就是“并发”。

分时复用是一种多用户共享计算机资源的操作系统技术,旨在实现多用户之间的公平资源分配、任务调度和交互,允许多个用户通过不同的终端或连接共享计算机系统,每个用户被分配一个时间片段来执行其任务,然后系统切换到下一个用户。这种技术的目标是在单台计算机上支持多个用户的并发访问,以提高计算资源的利用率。

这和“信道复用”很相似:

信道复用是一种通信技术,用于有效地共享通信信道或媒体以传输多个数据流或信号。它允许多个独立的通信流在相同的物理通信媒体上传输,从而提高了通信资源的利用效率。

信道复用通常用于数据通信、电话系统、无线通信和计算机网络等领域。

有两种主要的信道复用技术:时分复用(Time Division Multiplexing,TDM)和频分复用(Frequency Division Multiplexing,FDM)。

  1. 时分复用(TDM)

    • TDM将通信时间分割成若干个时隙(time slot),每个时隙用于传输不同的数据流或信号。
    • 不同通信流的数据在各自的时隙内传输,这样它们不会发生冲突。
    • TDM常用于电话系统中,其中多个电话线路可以在同一物理线上传输声音信号,每个电话线路占用一个时隙。
  2. 频分复用(FDM)

    • FDM将通信信道划分成不同的频率带宽段,每个带宽段用于传输不同的数据流或信号。
    • 不同通信流的数据在不同的频率带宽段内传输,这样它们不会互相干扰。
    • FDM常用于无线通信中,多个无线信号可以在同一频谱范围内传输,每个信号占用不同的频率带宽段。
  3. 码分复用(Code Division Multiplexing,CDM)

    • CDM是一种数字通信中的信道复用技术,它使用不同的编码序列来区分不同的数据流。
    • 每个数据流使用不同的编码序列,使其在同一时间传输,并在接收端使用正确的解码序列来还原数据。
    • CDM常用于无线通信中,如CDMA(Code Division Multiple Access)手机网络。

信道复用技术的选择取决于通信系统的需求和特性。它们可以提高通信信道的利用率,允许多个用户或设备同时共享通信资源,从而实现高效的数据传输和通信。

咱们说的通俗易懂一点就是,只要这些进程轮转的速度够快,看起来就好像是在同时运行一样,毕竟几纳秒的时间对于电脑来说可能有和大区别,但对于我们人类来说没有什么差别。 

你可以看到这里的速度是非常快的,一秒钟执行42.9亿条指令,足够很多进程轮转调度很多圈了!

好了,回神!

并发执行是对于单个核心CPU来说的,实际上现代的CPU都是多核心的……

如果两个进程同时在两个CPU核心上,微观上也是同时执行的,我们就把这个叫做“并行”。

而如果是只在一个CPU核心上,通过快速轮转调度的方式执行多个进程,宏观上是同时执行的,但是微观上却是有先后顺序的,这个叫做“并发”。

  1. 并行(Parallelism)

    • 并行是指多个任务或进程在同一时刻在多个独立的处理器核心(或计算单元)上同时执行。
    • 在并行处理中,每个任务具有自己的处理器核心,它们可以并行地执行,互不干扰。
    • 这种方式可以显著提高计算性能,特别适用于需要高吞吐量和计算密集型任务。
  2. 并发(Concurrency)

    • 并发是指多个任务或进程在同一时间段内交替执行,共享同一处理器核心或计算资源。
    • 在并发处理中,任务之间通过快速的轮转调度(时间片轮转等)交替执行,看起来好像它们在同时执行。
    • 这种方式用于有效地管理多个任务,特别适用于I/O密集型任务和多用户系统。

不管是“并行”还是“并发”,在应用程序这一层上我们都是感知不到的,这都是系统内部完成调度的。从编程角度来说,底层是并发还是并行对代码都没啥影响,所以平时我们也就会统一使用“并发”来代指“并行”和“并发”。

PCB中引入了一些属性用来支持操作系实现进程调度:

  1. 进程的状态

    • 进程可以处于不同的状态,通常包括就绪、运行、阻塞等。
    • 就绪状态:进程已准备好运行,但尚未分配CPU时间。
    • 运行状态:进程正在执行其指令,占用CPU。
    • 阻塞状态:进程暂时停止运行,等待某些事件(例如I/O操作完成或者是等待用户输入等)。也就是说,当某种执行条件不具备,就导致这个进程暂时无法参与CPU的调度执行。
    • 进程状态的切换由操作系统调度器负责管理,以实现多任务处理。
  2. 进程的优先级

    • 进程通常被分配一个优先级,用于决定在多任务环境中哪个进程应该首先执行。
    • 高优先级的进程将在竞争CPU时间时优先执行,而低优先级的进程则可能需要等待。
    • 进程的优先级可以是静态的(由管理员或程序员设置)或动态的(根据运行情况自动调整)。
  3. 进程的上下文

    • 进程的上下文是指进程在执行过程中的全部状态信息,包括寄存器的值、内存中的数据、程序计数器的值、打开的文件描述符等。
    • 上下文保存了进程的完整状态,允许操作系统在需要时切换进程执行,以便实现多任务处理。(进程从CPU离开之前们需要保存现场,把当前CPU中各种寄存器的状态都记录到内存中。等到下一次进程回到CPU上执行的时候,就可以把保存的这些寄存器的值恢复回去。进程就会沿着上次执行到的位置继续往后执行,类似于游戏的存档和读档)
    • 进程上下文切换是操作系统中的重要操作,用于保存当前执行进程的上下文并加载下一个进程的上下文。
    • CPU中有些寄存器属于没有特定含义,就只是用来保存运算的中间结果的。还有些寄存器是有特定含义和特定作用的:(1)、保存当前执行到的指令(程序计数器):一个2/4/8个字节的整数,存的是一个内存地址,这个地址是程序下一条要执行的指令所在的位置。exe 里面就包含了指令和数据,把 exe 运行起来,操作系统就会把指令和数据加载到内存中,就得到一个内存地址。CPU就会先从内存中取指令,然后执行指令。初始情况下,程序计数器的值就会自动更新,默认下会直接跳向下一条指令(按顺序执行),但是如果遇到跳转类指令(jump,jcmp,call……)就会被设置成应该跳转到的地址。  (2)、维护栈相关的寄存器:通过一组(一般是两个)寄存器来维护当前程序的“调用栈”。栈作为一块内存,就保存有当前这个程序方法调用过程中,一系列的关系(当然也包括局部变量和方法参数……),比如 ebp(始终执行栈底)和 esp(始终指向栈顶,修改它的值就可以实现“入栈”/“出栈”)(push指令完成上述操作)(3)、其他的通用寄存器,往往使用来保存计算的中间结果的。
  4. 进程的记账信息

    • 进程的记账信息用于记录进程的资源使用情况,如CPU时间、内存占用、打开的文件数等。
    • 我们先前提到通过优先级机制,对不同的进程分配了不同权重的资源。那么这就有可能会出现极端的情况,比如把所有的资源都给了其中某一个进程,其他进程一点资源都没有。而此时记账信息有助于系统管理员了解进程的行为和性能,以便进行性能分析和资源管理。
    • 操作系统通常提供工具和命令来查看和分析进程的记账信息,例如UNIX和Linux系统中的 ps 和 top 命令。 

以上属性在操作系统中起着关键作用,有助于有效管理和调度进程,确保多个任务能够在共享的计算资源上协调运行。同时,它们也为系统管理员和开发人员提供了有关进程行为和性能的重要信息。

操作系统调度器和调度算法 

操作系统的调度器是操作系统内核的一部分,它负责管理和控制多个进程之间的执行顺序,以实现多任务处理。调度器的主要任务是决定哪个进程应该获得CPU时间,并在多个进程之间进行切换。

以下是一些常见的调度算法,用于决定进程的执行顺序:

  1. 先来先服务(First-Come, First-Served,FCFS)

    • FCFS是一种简单的调度算法,按照进程到达的顺序分配CPU时间。
    • 先到达的进程先执行,后到达的进程排队等待。
    • 缺点是可能导致"饥饿"问题,即长任务在短任务前等待时间较长。
  2. 短作业优先(Shortest Job First,SJF)

    • SJF算法将CPU分配给估计执行时间最短的进程。
    • 这种方式最小化了平均等待时间,但需要准确估计进程的执行时间,对于无法准确估计的情况不适用。
  3. 优先级调度(Priority Scheduling)

    • 优先级调度根据进程的优先级分配CPU时间,优先级高的进程先执行。
    • 可以根据不同的优先级策略进行调度,如静态优先级或动态优先级。
    • 静态优先级由管理员或程序员指定,而动态优先级可能根据进程的行为自动调整。
  4. 轮转调度(Round Robin,RR)

    • 轮转调度算法将CPU时间划分成时间片(时间量子),每个进程在一个时间片内执行,然后切换到下一个进程。
    • 这种方式确保每个进程都有机会执行,避免了"饥饿"问题。
    • 时间片的大小可以根据系统需求进行调整。
  5. 多级反馈队列调度(Multilevel Feedback Queue Scheduling)

    • 多级反馈队列调度算法将进程按照优先级划分成多个队列,每个队列使用不同的调度策略。
    • 进程首先进入高优先级队列,然后根据其执行行为和时间在不同队列之间切换。
    • 这种方式可以适应不同类型的进程,如I/O密集型和CPU密集型。
  6. 最高响应比优先(Highest Response Ratio Next,HRRN)

    • HRRN算法根据响应比来选择下一个执行的进程,响应比定义为(等待时间 + 服务时间)/ 服务时间。
    • 这种方式尝试平衡短作业和长作业的执行,以最大程度地减少等待时间。

不同的调度算法适用于不同的应用场景和需求。操作系统通常会根据系统性能和特定任务的需求选择合适的调度算法。一些操作系统甚至支持多种调度算法,以便根据不同的任务类型和工作负载动态选择最佳算法。

虚拟地址空间

我们刚刚讲内存指针的时候提到了一个概念——“虚拟地址空间”。

早期的操作系统,程序运行的时候分配的内存是物理内存。

RAM:

如上图,如果B进程越界访问了A进程的内存,把A的内存写成错误的值,那么就极有可能导致A进程崩溃……

可是我们之前说了,操作系统要给进程提供稳定的运行环境啊!

因此,操作系统引入了“虚拟地址空间”概念,不是直接分配物理内存了,而是分配虚拟的内存空间。也就是说操作系统对于内存又进行了一层抽象。

虚拟地址空间将物理内存的细节抽象化了。进程不需要知道物理内存的具体位置或大小,它只需关注它自己的虚拟地址空间。这允许操作系统有效地管理物理内存,包括内存分配、释放和内存页的置换。

A操作某个内存中的数据,就需要把操作系统的虚拟地址告诉系统,系统再把虚拟地址翻译成物理地址(有一个类似于Hash表这样的映射结构,称为页表),再操作物理地址。

操作系统使用页表或段表等数据结构来执行虚拟地址到物理地址的翻译。这个翻译过程使得虚拟地址在运行时动态映射到物理地址。如果进程尝试访问一个无效或越界的虚拟地址,操作系统会检测到这种情况并终止该进程,从而保护系统的稳定性,并且不会波及到其他进程。

这样的机制就带来了一个进程很重要的特性——独立性。

隔离性和独立性: 每个运行的进程都有自己的虚拟地址空间,这个虚拟地址空间是由操作系统分配的,对其他进程来说是不可见的。这意味着一个进程不能直接访问或修改另一个进程的内存。这种隔离性和独立性是操作系统的重要特性之一,它有助于确保进程之间的互相干扰最小化。

通过上述方式,我们确实把进程给隔离开了。但是如果某个需求中,我们确实就需要让多个进程相互配合、交互数据,那该怎么办好?

此处就需要引入新的机制来实现进程之间的通信。

进程之间相互协作和交互数据

“为不同的进程提供一种机制,使它们能够在需要时相互协作和交换数据”有很多方式,它们的核心思想大致分为以下两种:

  1. 共享内存模型: 在这种模型下,多个进程可以访问和修改同一块共享的物理内存区域。这就意味着它们可以直接读取和写入相同的内存位置,实现了高效的数据共享。但是,这种方法需要非常小心地进行同步和互斥操作,以避免数据竞争和一致性问题。

    例子:共享内存、内存映射文件等。
  2. 消息传递模型: 在这种模型下,进程之间通过发送和接收消息进行通信。每个进程拥有自己的私有内存空间,而通信是通过操作系统或网络进行的。这种方法更安全,因为进程之间不能直接访问彼此的内存,但它需要额外的消息传递机制。

    例子:管道、消息队列、套接字、远程过程调用(RPC)等。

共享内存适用于需要高效共享大量数据的场景,但需要保证数据一致性。消息传递适用于更安全的通信,但可能会引入一些额外的开销,例如消息传递的封装和解封装。选择哪种模型取决于应用程序的需求和设计目标。

我们这里主要看看第一种思路。

具体的实现方式有很多,但是每个方式的核心思想都是一样的——“借助一个公共空间,完成数据的交互”。下面介绍两种方式:

  1. 通过文件:

    • 核心思想: 进程可以通过读写共享文件来进行数据交互。文件是一种持久性存储介质,进程可以将数据写入文件,然后其他进程可以读取同一文件的数据。

    • 使用场景: 通常在本地文件系统中使用,适合需要持久性数据存储和共享的场景。多个进程可以通过访问相同的文件来交换信息,但需要考虑同步和互斥问题以防止数据冲突。

  2. 通过网络(Socket):

    • 核心思想: 进程可以通过套接字(Socket)在网络上进行通信。套接字提供了一种网络连接,允许进程在不同的计算机上进行数据交互。通信可以是基于传输层协议(如TCP或UDP)的。

    • 使用场景: 适用于分布式系统和远程通信场景。它允许不同计算机上的进程相互通信,包括客户端-服务器通信和对等通信。Socket通信可以跨越互联网,使远程进程能够交换数据。

这两种方式都允许进程之间在一个共享的环境中进行数据交互,但它们的适用场景和使用方式有所不同。通过文件适用于本地数据存储和共享,通常用于单一计算机上的进程之间。通过网络(Socket)适用于分布式系统、远程通信和多计算机环境下的进程通信,可以在不同计算机之间传输数据。选择哪种方式取决于我们的具体需求和应用程序的设计。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/151101
推荐阅读
相关标签
  

闽ICP备14008679号