Linux进程(1)

news2025/1/8 4:35:10

在这里插入图片描述

目录

  • ⛹🏽进程简介
  • ⛹🏽查看进程
  • ⛹🏽系统调用
    • 🚴🏽获取进程标示符
    • 🚴🏽创建进程
  • ⛹🏽进程状态
    • 🚴🏽孤儿进程:
    • 🚴🏽进程优先级
  • ⛹🏽环境变量
    • 🚴🏽查看环境变量
    • 🚴🏽添加环境变量
    • 🚴🏽组织环境变量
    • 🚴🏽获取环境变量
    • 🚴🏽环境变量特性
  • ⛹🏽进程地址空间
  • ⛹🏽总结

⛹🏽进程简介

进程概念:程序的一个执行实例或者一个担当分配系统资源(CPU时间,内存)的实体。

进程描述:进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合,简称为PCB(process control block),在Linux操作系统下的PCB是: task_structtask_struct是PCB的一种,task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。

task_ struct内容分类:

标示符: 描述本进程的唯一标示符,用来区别其他进程。

状态: 任务状态,退出代码,退出信号等。

优先级: 相对于其他进程的优先级。

程序计数器: 程序中即将被执行的下一条指令的地址。

内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针

上下文数据: 进程执行时处理器的寄存器中的数据。

I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。

记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。

其他信息

组织进程:在内核源代码里,所有运行在系统里的进程都以task_struct链表的形式存在内核里。

⛹🏽查看进程

进程的信息可以通过 /proc系统文件夹查看,如下图:

在这里插入图片描述

大多数进程信息同样可以使用ps这些用户级工具来获取,例如我们也可以写一个程序运行然后使用ps命令来查看该进程,如下代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
  	while(1){
		printf("正在运行\n");
		sleep(1);
    }
    return 0;
}

编译运行,然后使用命令ps axj | grep test1 | grep -v grep查看进程。

在这里插入图片描述

⛹🏽系统调用

🚴🏽获取进程标示符

进程的标识符id称为PID,进程的父进程标识符id成为PPID。

系统给我们分别提供了获取PID和PPID的函数——getpid()getppid()


通过查看手册可以看到,使用这两个函数我们需要包含sys/types.hunistd.h这两个头文件,并且getpid返回当前的进程id,getppid返回当前进程的父进程的id。

我们可以在自己的代码中使用系统提供给我们的两种系统调用函数来获取进程的PID和PPID,如下代码:

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <sys/types.h>
  4 int main()
  5 {
  6   while(1){
  7     printf("正在运行,我的PID为:%d,我的PPID为:%d\n", getpid(), getppid());                         
  8     sleep(1);
  9   }
 10   return 0;
 11 }

在这里插入图片描述

我们还可以用ps命令来查看进程,如下图:

在这里插入图片描述

🚴🏽创建进程

在系统接口中,还给我们提供了创建子进程的函数——fork()

查看手册可以看到,使用fork函数我们需要包含unistd.h这个头文件,当子进程成功创建时,将子进程的id返回给他的父亲,返回0给他自己,如果创建失败则返回-1给他的父亲。

如下代码:

 22 int main()
 23 {
 24     int ret = fork();
 25     if(ret > 0)
 26     {
 27       while(1)
 28       {
 29         printf("我是父进程,pid: %d, ppid: %d\n", getpid(), getppid());
 30         sleep(1);                 
 31       }
 32     }
 33     else if (ret == 0)
 34     { 
 35       while(1)
 36       {
 37          printf("我是子进程,pid:%d, ppid: %d\n", getpid(), getppid());
 38          sleep(1);
 39       }
 40     }
 41     else{
 42       printf("error\n");
 43     }
 44     return 0;
 45 }

在这里插入图片描述

由结果可以看到,子进程的PPID和父进程的PID一样。可能你会觉得这个结果很奇怪,为什么只有一个ret,但是却把if和else都执行了,这是因为我们使用fork创建子进程后,代码就是父子进程共享,数据各自开辟空间,私有一份,在返回时发生写时拷贝。

如下代码:

 21 int main()
 22 {
 23   printf("aaaaaaaaaaaaaaaaaa\n");
 24   fork();
 25   printf("bbbbbbbbbbbbbbbbb\n");
 26   return 0;   
 27 }

在这里插入图片描述

⛹🏽进程状态

为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有如下几种状态:

  • R运行状态(running):并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

  • S睡眠状态(sleeping):意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。

  • D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

  • X死亡状态(dead):这个状态只是一个返回状态,在任务列表里看看不到这个状态。

  • Z(zombie)-僵尸进程(僵死状态(Zombies)):是一个比较特殊的状态。
    当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程,僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。

我们可以用代码来观察僵尸进程,如下代码:

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <sys/types.h>
  4 
  5 int main()
  6 {
  7   int ret = fork();
  8   if(ret == 0)
  9   {
 10     for(int i = 5; i > 0; i--)
 11     {
 12       printf("我是子进程%d,我的父进程%d,结束还有%d秒\n", getpid(), getppid(), i);
 13       sleep(1);
 14     }
 15   }
 16   else if (ret > 0)
 17   {
 18     for(int i = 10; i > 0; i--)
 19     {
 20       printf("我是父进程%d,我的子进程%d,结束还有%d秒\n", getpid(), getppid(), i);                                                        
 21       sleep(1);
 22     }
 23   }
 24   else{
 25     printf("eroor\n");
 26   }
 27   return 0;
 28 }

编译运行该程序后我们可以在xshell上运行ps命令来观察进程状态.

命令:while :; do ps axj | head -1 && ps axj | grep test1 | grep -v grep;sleep 1;echo "===============================";done

在这里插入图片描述

如上图我们可以看出,当子进程退出的时候,他的状态由s(sleep)转换为z(zombie)。

僵尸进程危害:

  • 进程的退出状态必须被维持下去,因为他要告诉它的父进程。可父进程如果一直不读取,那子进程就一直处于僵尸状态。

  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,也就是说,如果僵尸状态一直不退出,PCB一直都要维护!

  • 那一个父进程创建了很多子进程,就是不回收,就会造成内存资源的浪费!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间! 就会造成内存泄漏。

🚴🏽孤儿进程:

当我们的父进程如果提前退出,那么子进程后退出,在子进程进入僵尸进程之后,那该如何处理呢?

我们称这种父进程先退出,子进程后退出,把这种子进程就称之为“孤儿进程”

这种孤儿进程通常是被1号init进程回收领养

我们也可以用一段代码来观察,如下代码:

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <sys/types.h>
  4 
  5 int main()                                                                                                 
  6 {
  7   int ret = fork();
  8   if(ret == 0)
  9   {
 10     for(int i = 10; i > 0; i--)
 11     {
 12       printf("我是子进程%d,我的父进程%d,结束还有%d秒\n", getpid(), getppid(), i);
 13       sleep(1);
 14     }
 15   }
 16   else if (ret > 0)
 17   {
 18     for(int i = 5; i > 0; i--)
 19     {
 20       printf("我是父进程%d,我的子进程%d,结束还有%d秒\n", getpid(), getppid(), i);
 21       sleep(1);
 22     }
 23   }
 24   else{
 25     printf("eroor\n");
 26   }
 27   return 0;
 28 }

用ps命令来查看进程状态

while :; do ps axj | head -1 && ps axj | grep test1 | grep -v grep;sleep 1;echo "===============================";done

在这里插入图片描述
如上图我们可以看到,当父进程退出后,我们的子进程就会更换自己的父进程。

🚴🏽进程优先级

cpu资源分配的先后顺序,就是指进程的优先权(priority),优先权高的进程有优先执行权利。

配置进程优先权对多任务环境的linux很有用,可以改善系统性能。还可以把进程运行到指定的CPU上。

这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

查看系统进程:

在linux或者unix系统中,用ps –l命令则会类似输出以下几个内容

在这里插入图片描述

我们可以看到有如下几个重要信息

UID : 代表执行者的身份

PID : 代表这个进程的代号

PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号

PRI :代表这个进程可被执行的优先级,其值越小越早被执行

NI :代表这个进程的nice值

其中,PRI就是进程的优先级,通俗点说就是程序被CPU执行的先后顺序,PRI值越小进程的优先级别越高。

NI就是nice值,其表示进程可被执行的优先级的修正数值

PRI值越小越快被执行,在加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice

这样,当nice值为负值的时候,那么该程序的优先级值将变小,即其优先级会变高,则其越快被执行

所以,调整进程优先级,在Linux下,就是调整进程nice值,nice值取值范围是-20至19,一共40个级别。

需要注意的一点是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。

可以理解nice值是进程优先级的修正修正数据

查看进程优先级的命令:top

用top命令更改已存在进程的nice,进入top后按“r”然后输入进程PID再输入nice值。

在这里插入图片描述
如上图,当我们将test1的进程NI值修改为10之后,我们可以看到test1的PRI值变为30。

⛹🏽环境变量

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数

如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

常见环境变量:

PATH : 指定命令的搜索路径

HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)

SHELL : 当前Shell,它的值通常是/bin/bash。

🚴🏽查看环境变量

命令:echo $NAME

NAME为你的环境变量名称,例如echo $USER
在这里插入图片描述

🚴🏽添加环境变量

我们都知道,当我们编译好一份代码文件时,如果我们想运行这个代码文件,我们需要在前面加上./,这个./是在当前路径下查找你所要执行的文件。

但是为什么有些指令可以直接执行,不需要带路径,而我们的二进制程序需要带路径才能执行?

因为这些指令在环境变量中存有他的路径,当我们执行这些指令时,会在环境变量所保存的路径中去查找该指令。

我们可以用命令echo $PATH来查看我们的环境变量,如下图:
在这里插入图片描述

我们可以将我们的程序所在路径加入环境变量PATH当中,然后查看与之前有什么不同。将程序路径加入到环境变量中我们可以使用命令:

export PATH=$PATH:[我们文件所在的路径]

例如当前有这么一个.c文件,如下代码:

  1 #include <stdio.h>
  2 
  3 int main()
  4 {
  5   for(int i = 0; i < 5; i++)
  6   {
  7     printf("hello world\n");
  8   }                                                                                                                                                                 
  9   return 0;
 10 }

我们当前所处路径为/home/wzh/linux/Test23_4_21

在这里插入图片描述

我们将该路径加入到PATH环境变量中去,执行命令export PATH=$PATH:/home/wzh/linux/Test23_4_21

在这里插入图片描述

之后我们可以发现,我们不需要带./也是可以运行我们的程序,如下图:
在这里插入图片描述

🚴🏽组织环境变量

每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以\0结尾的环境字符串

在这里插入图片描述

🚴🏽获取环境变量

我们可以通过代码来获取环境变量,例如我们可以通过main函数的第三个参数来获取,如下代码:

    1 #include <stdio.h>
    2 
  	3 int main(int argc, char* argv[], char* env[])
    4 {
    5   for(int i = 0; env[i]; i++)
    6   {
    7     printf("%s\n", env[i]);                                                                                                                                       
    8   }
    9 
   10   return 0;
   11 }

在这里插入图片描述

除了参数获取,我们还可以通过第三方变量environ获取,如下代码

   16 #include <stdio.h>
   17 int main(int argc, char* argv[])
   18 {
   19   extern char** environ;
   20   for(int i = 0; environ[i]; i++)
   21     printf("%s\n", environ[i]);                                            
   22   return 0;
   23 }

在这里插入图片描述

libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明。

除了使用代码参数和变量查看我们的环境变量,我们还可以通过系统调用接口来获取环境变量,系统给我们提供了一个getenv()函数,如下图:

在这里插入图片描述

我们可以看出,这个函数是包含在stdlib.h这个头文件中,因此我们在使用这个函数的时候还得包这个头文件,如下代码:

 26 #include <stdio.h>
 27 #include <stdlib.h>
 28 int main()
 29 {
 30   printf("%s\n", getenv("PATH"));                                                           
 31   return 0;
 32 }

在这里插入图片描述

🚴🏽环境变量特性

环境变量通常是具有全局属性,可以被子进程继承下去。如下代码:

 26 #include <stdio.h>
 27 #include <stdlib.h>
 28 int main()
 29 {
 31   char* ret = getenv("testenv");                                                        
 32   if(ret)
 33     printf("%s\n", ret);
 34   return 0;
 35 }

当我们编译运行的时候发现什么都没有打印出来,说明不存在这个环境变量,但是当我们用命令export testenv="hello world"的时候再次运行会发现这个时候就打印出来hello world。

在这里插入图片描述

⛹🏽进程地址空间

在我们基于32位平台下,我们知道有如下图所示的地址空间分布

在这里插入图片描述

但是有这么一份奇怪的代码:

 40 #include <sys/types.h>
 41 #include <stdio.h>
 42 #include <unistd.h>
 43 #include <stdlib.h>
 44 int main()
 45 {
 46   int val = 0;
 47   pid_t ret = fork();
 48   if(ret == 0)
 49   {
 50     for(int i = 0; i < 5; i++)
 51     {
 52       val++;
 53       printf("child : %d childpid : %d address : %p\n", val, getpid(), &val);
 54       sleep(1);
 55     }
 56   }
 57   else if (ret > 0)
 58   {
 59     for(int i = 0; i < 5; i++)
 60     {
 61       val += 10;                                                                                                                                                    
 62       printf("father : %d fatherpid : %d address : %p\n", val, getpid(), &val);
 63       sleep(1);
 64     }
 65   }
 66   else{
 67     perror("fork");
 68   }
 69   return 0;
 70 }

在我们运行后发现结果如图所示
在这里插入图片描述

我们都知道进程与进程之间是独立的,所以子进程和父进程的val值修改互相并不影响,但是我们观察运行结果我们可以看到,子进程和父进程的val值地址都是一样的,如果它们地址是一样的那么父子进程的val就应该是同一个val,可是如果是同一个val那么他们修改又怎么会互不影响呢。所以我们大概就可以得出下面的结论:

变量内容不一样,所以父子进程输出的变量绝对不是同一个变量

该地址绝对不是物理地址

这样的地址在Linux下,我们把这种地址叫做虚拟地址,我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址用户一概看不到,由操作系统统一管理,操作系统必须负责将虚拟地址转化成物理地址 。因此我们所说的程序地址空间严格的说是不准确的,应该叫进程地址空间。

当我们的程序编译运行变为一个进程的时候,其中PCB(task_struct)中的某个指针就会指向一块虚拟地址空间,而虚拟地址空间又会由页表进行映射到物理内存上,如下图:
在这里插入图片描述

⛹🏽总结

本篇博客介绍了Linux的一些进程状态,环境变量,以及进程地址空间和一些系统调用接口,用代码来看现象。如果觉得本篇博客对你有帮助的话就三连吧!另外由于作者水平有限,如果文中有什么纰漏或者错误还请指正。谢谢大家。
在这里插入图片描述

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

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

相关文章

一次使用netcat的经验记录

1.netcat安装 参考&#xff1a;https://my.oschina.net/u/3530967/blog/1560985 2.netcat使用 参考&#xff1a;https://zhuanlan.zhihu.com/p/83959309 3.创建udp服务 &#xff08;1&#xff09;使用&#xff1a;nc -l -u -p 8810 创建udp服务端监听8810端口 在另一台机…

基于信度感知的半监督医学图像分类对比自集成

文章目录 Reliability-Aware Contrastive Self-ensembling for Semi-supervised Medical Image Classification摘要本文方法Reliability-Aware Contrastive Mean TeacherWeight FunctionReliability-Aware Consistency LossReliability-Aware Contrastive LossObjective Functi…

windows 安装mysql5.7

确认是否安装了mysql winr 输入services.msc , 找mysql 下载 链接&#xff1a;https://pan.baidu.com/s/1zPuvzjWovky3MrpNlIt9uw 提取码&#xff1a;y52i 安装 https://blog.csdn.net/u012318074/article/details/124042756 家目录下新建配置文件 my.ini 注意路径中 // &a…

企业进行数字化转型的优劣势分别有哪些?

数字化转型是指将数字技术融入企业的方方面面&#xff0c;从而导致企业运营方式和为客户创造价值的方式发生根本性变化。企业数字化转型既有优势也有劣势&#xff0c;概述如下&#xff1a; 优点&#xff1a; 提高效率和生产力&#xff1a;数字化转型使企业能够自动化和简化业…

Session服务端会话追踪

1. Session基本使用 将数据&#xff08;cookie&#xff09;保存在客户端不安全&#xff0c;因为客户端在不停的进行着网络传输&#xff0c;所以把数据存储在服务端。 存储的对象就是session&#xff0c;例如AServlet往session中存数据&#xff0c;BServlet往session中读数据。 …

纯 CSS 实现几个 Loading 效果

1. 平滑加载 <div class"progress-1"></div>.progress-1 {width:120px;height:20px;background:linear-gradient(#000 0 0) 0/0% no-repeat#ddd;animation:p1 2s infinite linear; } keyframes p1 {100% {background-size:100%} }linear-gradient(#000 0…

11.java程序员必知必会类库之word处理库

前言 正常业务中&#xff0c;可能涉及到和合作方签约电子合同&#xff0c;此时&#xff0c;我们需要先设计合同模板&#xff0c;维护固定内容&#xff0c;将可变的内容通过占位符替代&#xff0c;等签章的时候&#xff0c;生成pdf,然后可以根据设计的合同章的坐标&#xff0c;…

家庭私人影院 - Windows搭建Emby媒体库服务器并远程访问 「无公网IP」

文章目录 1.前言2. Emby网站搭建2.1. Emby下载和安装2.2 Emby网页测试 3. 本地网页发布3.1 注册并安装cpolar内网穿透3.2 Cpolar云端设置3.3 Cpolar内网穿透本地设置 4.公网访问测试5.结语 1.前言 在现代五花八门的网络应用场景中&#xff0c;观看视频绝对是主力应用场景之一&…

第十章_Redis集群(cluster)

是什么 定义 由于数据量过大&#xff0c;单个Master复制集难以承担&#xff0c;因此需要对多个复制集进行集群&#xff0c;形成水平扩展每个复制集只负责存储整个数据集的一部分&#xff0c;这就是Redis的集群&#xff0c;其作用是提供在多个Redis节点间共享数据的程序集。 官…

cad怎么转换成pdf格式,3个方法快速搞定

cad怎么转换成pdf格式&#xff1f;首先我们来了解一下CAD是什么。CAD是一种计算机辅助设计软件&#xff0c;其文件格式为DWG&#xff08;Drawing&#xff09;和DXF&#xff08;Drawing Exchange Format&#xff09;。DWG是CAD程序的本地文件格式&#xff0c;用于存储2D和3D图形…

【LLM】LLaMA简介:一个650亿参数的基础大型语言模型

LLaMA简介&#xff1a;一个650亿参数的基础大型语言模型 PaperSetup其他资料 作为 Meta 对开放科学承诺的一部分&#xff0c;今天我们将公开发布 LLaMA (大型语言模型 Meta AI) &#xff0c;这是一个最先进的大型语言基础模型&#xff0c;旨在帮助研究人员推进他们在人工智能这…

刘宇:如何打造快、稳、易、专的多元数据库运行平台

导语 4月8日下午&#xff0c;为期两天的第十二届数据技术嘉年华&#xff08;DTC 2023&#xff09;在北京新云南皇冠假日酒店圆满落下帷幕。大会以“开源融合数字化——引领数据技术发展&#xff0c;释放数据要素价值”为主题&#xff0c;汇聚产学研各界精英到场交流。云和恩墨作…

直面GPT-4的缺陷和风险,OpenAI提出多种安全应对措施

深入研究OpenAI官方团队发布的长达99页的技术报告&#xff0c;我们发现在GPT-4光鲜亮丽功能的背后&#xff0c;还隐藏了OpenAI团队付出的的汗水和努力&#xff0c;尤其是在缓解GPT模型自身缺陷和模型安全落地方面。 报告链接&#xff1a; https://arxiv.org/abs/2303.08774 一、…

UEditorPlus v3.0.0 样式CSS变量,支持Mind代码类型,若干问题修复

UEditor是由百度开发的所见即所得的开源富文本编辑器&#xff0c;基于MIT开源协议&#xff0c;该富文本编辑器帮助不少网站开发者解决富文本编辑器的难点。 UEditorPlus 是有 ModStart 团队基于 UEditor 二次开发的富文本编辑器&#xff0c;主要做了样式的定制&#xff0c;更符…

kafka单节点快速搭建

1.搭建使用centos7主机&#xff0c;关闭防火墙和selinux服务 2.创建kafka存放目录 mkdir /etc/kafka 3.从kafka官网下载安装包 我这里下载了3.3.1版本的kafka&#xff0c;放到kafka目录中 下载地址&#xff1a;Apache Kafka 4.解压安装包并更改名称 tar -zxvf /etc/kaf…

Three.js教程:顶点索引复用顶点数据

推荐&#xff1a;将 NSDT场景编辑器 加入你3D工具链 其他工具系列&#xff1a; NSDT简石数字孪生 顶点索引复用顶点数据 通过几何体BufferGeometry的顶点索引属性BufferGeometry.index可以设置几何体顶点索引数据&#xff0c;如果你有WebGL基础很容易理解顶点索引的概念&#…

如何建立Linux与git的连接?

文章目录 建立连接三板斧&#xff1a; 本文以Xshell为案例进行与git的连接&#xff01; 建立连接三板斧&#xff1a; add , commit ,push Linux与git远程连接的方法&#xff1a; 1.设置全局的用户名和邮箱 git config – global user.name “你的用户名” git config – glo…

JMeter学习(一)工具简单介绍

一、JMeter 介绍 Apache JMeter是100%纯JAVA桌面应用程序&#xff0c;被设计为用于测试客户端/服务端结构的软件(例如web应用程序)。它可以用来测试静态和动态资源的性能&#xff0c;例如&#xff1a;静态文件&#xff0c;Java Servlet,CGI Scripts,Java Object,数据库和FTP服务…

gpt国内怎么用-gpt国内版免费下载使用

gpt免费使用 GPT (Generative Pre-trained Transformer) 是一种非常强大的语言模型&#xff0c;它是由 OpenAI 开发的&#xff0c;用于自然语言处理和生成。GPT 可以生成高质量、流畅、自然的文本&#xff0c;帮助用户实现更加高效的写作和沟通。现在&#xff0c;GPT 免费使用…

Cookie客户端会话技术

1. Cookie基本使用 过程&#xff1a; 当浏览器发出请求1给服务器端A时&#xff0c;A Servlet就会创建一个cookie对象数据&#xff0c;A在做响应时&#xff0c;就会发送给浏览器&#xff0c;浏览器就把cookie保存在内存之中&#xff1b; 当浏览器在同一次会话中&#xff0c;再次…