热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c语言僵尸进程,植物大战僵尸c语言程序

本文目录一览:1、创建子进程实现shell所有命令C语言linux

本文目录一览:


  • 1、创建子进程实现shell所有命令 C语言 linux


  • 2、linux下的PID,PIDD是什么?他们之间的关系以及应用是什么?


  • 3、c语言 在一个线程上开辟一段内存;


  • 4、Linux C函数Kill

创建子进程实现shell所有命令 C语言 linux

在这里不要用scanf,用gets好了。

scanf在输入中如果遇到空格就会跳掉.gets没问题

linux下的PID,PIDD是什么?他们之间的关系以及应用是什么?

在 Linux 底下执行一个指令时,系统会给予这个动作一个 ID, 我们称为 PID,而根据启用这个指令的使用者与相关的指令功能,而给予这个特定 PID 一组权限, 该指令可以进行的行为则与这个 PID 的权限有关。

linux进程简介

Linux是一个多任务的操作系统,也就是说,在同一个时间内,可以有多个进程同时执行。如果读者对计算机硬件体系有一定了解的话,会知道我们大家常用的单CPU计算机实际上在一个时间片断内只能执行一条指令,那么Linux是如何实现多进程同时执行的呢?原来Linux使用了一种称为"进程调度(process scheduling)"的手段,首先,为每个进程指派一定的运行时间,这个时间通常很短,短到以毫秒为单位,然后依照某种规则,从众多进程中挑选一个投入运行,其他的进程暂时等待,当正在运行的那个进程时间耗尽,或执行完毕退出,或因某种原因暂停,Linux就会重新进行调度,挑选下一个进程投入运行。因为每个进程占用的时间片都很短,在我们使用者的角度来看,就好像多个进程同时运行一样了。

在Linux中,每个进程在创建时都会被分配一个数据结构,称为进程控制块(Process Control Block,简称PCB)。PCB中包含了很多重要的信息,供系统调度和进程本身执行使用,其中最重要的莫过于进程ID(process ID)了,进程ID也被称作进程标识符,是一个非负的整数,在Linux操作系统中唯一地标志一个进程,在我们最常使用的I386架构(即PC使用的架构)上,一个非负的整数的变化范围是0-32767,这也是我们所有可能取到的进程ID。其实从进程ID的名字就可以看出,它就是进程的身份证号码,每个人的身份证号码都不会相同,每个进程的进程ID也不会相同。

一个或多个进程可以合起来构成一个进程组(process group),一个或多个进程组可以合起来构成一个会话(session)。这样我们就有了对进程进行批量操作的能力,比如通过向某个进程组发送信号来实现向该组中的每个进程发送信号。

最后,让我们通过ps命令亲眼看一看自己的系统中目前有多少进程在运行:

$ps -aux(以下是在我的计算机上的运行结果,你的结果很可能与这不同。)

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

root 1 0.1 0.4 1412 520 ? S May15 0:04 init [3]

root 2 0.0 0.0 0 0 ? SW May15 0:00 [keventd]

root 3 0.0 0.0 0 0 ? SW May15 0:00 [kapm-idled]

root 4 0.0 0.0 0 0 ? SWN May15 0:00 [ksoftirqd_CPU0]

root 5 0.0 0.0 0 0 ? SW May15 0:00 [kswapd]

root 6 0.0 0.0 0 0 ? SW May15 0:00 [kreclaimd]

root 7 0.0 0.0 0 0 ? SW May15 0:00 [bdflush]

root 8 0.0 0.0 0 0 ? SW May15 0:00 [kupdated]

root 9 0.0 0.0 0 0 ? SW May15 0:00 [mdrecoveryd]

root 13 0.0 0.0 0 0 ? SW May15 0:00 [kjournald]

root 132 0.0 0.0 0 0 ? SW May15 0:00 [kjournald]

root 673 0.0 0.4 1472 592 ? S May15 0:00 syslogd -m 0

root 678 0.0 0.8 2084 1116 ? S May15 0:00 klogd -2

rpc 698 0.0 0.4 1552 588 ? S May15 0:00 portmap

rpcuser 726 0.0 0.6 1596 764 ? S May15 0:00 rpc.statd

root 839 0.0 0.4 1396 524 ? S May15 0:00 /usr/sbin/apmd -p

root 908 0.0 0.7 2264 1000 ? S May15 0:00 xinetd -stayalive

root 948 0.0 1.5 5296 1984 ? S May15 0:00 sendmail: accepti

root 967 0.0 0.3 1440 484 ? S May15 0:00 gpm -t ps/2 -m /d

wnn 987 0.0 2.7 4732 3440 ? S May15 0:00 /usr/bin/cserver

root 1005 0.0 0.5 1584 660 ? S May15 0:00 crond

wnn 1025 0.0 1.9 3720 2488 ? S May15 0:00 /usr/bin/tserver

xfs 1079 0.0 2.5 4592 3216 ? S May15 0:00 xfs -droppriv -da

daemon 1115 0.0 0.4 1444 568 ? S May15 0:00 /usr/sbin/atd

root 1130 0.0 0.3 1384 448 tty1 S May15 0:00 /sbin/mingetty tt

root 1131 0.0 0.3 1384 448 tty2 S May15 0:00 /sbin/mingetty tt

root 1132 0.0 0.3 1384 448 tty3 S May15 0:00 /sbin/mingetty tt

root 1133 0.0 0.3 1384 448 tty4 S May15 0:00 /sbin/mingetty tt

root 1134 0.0 0.3 1384 448 tty5 S May15 0:00 /sbin/mingetty tt

root 1135 0.0 0.3 1384 448 tty6 S May15 0:00 /sbin/mingetty tt

root 8769 0.0 0.6 1744 812 ? S 00:08 0:00 in.telnetd: 192.1

root 8770 0.0 0.9 2336 1184 pts/0 S 00:08 0:00 login -- lei

lei 8771 0.1 0.9 2432 1264 pts/0 S 00:08 0:00 -bash

lei 8809 0.0 0.6 2764 808 pts/0 R 00:09 0:00 ps -aux

以上除标题外,每一行都代表一个进程。在各列中,PID一列代表了各进程的进程ID,COMMAND一列代表了进程的名称或在Shell中调用的命令行,对其他列的具体含义,我就不再作解释,有兴趣的读者可以去参考相关书籍。

getpid

在2.4.4版内核中,getpid是第20号系统调用,其在Linux函数库中的原型是:

#includesys/types.h /* 提供类型pid_t的定义 */

#includeunistd.h /* 提供函数的定义 */

pid_t getpid(void);

getpid的作用很简单,就是返回当前进程的进程ID,请大家看以下的例子:

/* getpid_test.c */

#includeunistd.h

main()

{

printf("The current process ID is %d

",getpid());

}

细心的读者可能注意到了,这个程序的定义里并没有包含头文件sys/types.h,这是因为我们在程序中没有用到pid_t类型,pid_t类型即为进程ID的类型。事实上,在i386架构上(就是我们一般PC计算机的架构),pid_t类型是和int类型完全兼容的,我们可以用处理整形数的方法去处理pid_t类型的数据,比如,用"%d"把它打印出来。

编译并运行程序getpid_test.c:

$gcc getpid_test.c -o getpid_test

$./getpid_test

The current process ID is 1980

(你自己的运行结果很可能与这个数字不一样,这是很正常的。)

再运行一遍:

$./getpid_test

The current process ID is 1981

正如我们所见,尽管是同一个应用程序,每一次运行的时候,所分配的进程标识符都不相同。

fork

在2.4.4版内核中,fork是第2号系统调用,其在Linux函数库中的原型是:

#includesys/types.h /* 提供类型pid_t的定义 */

#includeunistd.h /* 提供函数的定义 */

pid_t fork(void);

只看fork的名字,可能难得有几个人可以猜到它是做什么用的。fork系统调用的作用是复制一个进程。当一个进程调用它,完成后就出现两个几乎一模一样的进程,我们也由此得到了一个新进程。据说fork的名字就是来源于这个与叉子的形状颇有几分相似的工作流程。

在Linux中,创造新进程的方法只有一个,就是我们正在介绍的fork。其他一些库函数,如system(),看起来似乎它们也能创建新的进程,如果能看一下它们的源码就会明白,它们实际上也在内部调用了fork。包括我们在命令行下运行应用程序,新的进程也是由shell调用fork制造出来的。fork有一些很有意思的特征,下面就让我们通过一个小程序来对它有更多的了解。

/* fork_test.c */

#includesys/types.h

#inlcudeunistd.h

main()

{

pid_t pid;

/*此时仅有一个进程*/

pid=fork();

/*此时已经有两个进程在同时运行*/

if(pid0)

printf("error in fork!");

else if(pid==0)

printf("I am the child process, my process ID is %d

",getpid());

else

printf("I am the parent process, my process ID is %d

",getpid());

}

编译并运行:

$gcc fork_test.c -o fork_test

$./fork_test

I am the parent process, my process ID is 1991

I am the child process, my process ID is 1992

看这个程序的时候,头脑中必须首先了解一个概念:在语句pid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的代码部分完全相同,将要执行的下一条语句都是if(pid==0)......。

两个进程中,原先就存在的那个被称作"父进程",新出现的那个被称作"子进程"。父子进程的区别除了进程标志符(process ID)不同外,变量pid的值也不相同,pid存放的是fork的返回值。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

在父进程中,fork返回新创建子进程的进程ID;

在子进程中,fork返回0;

如果出现错误,fork返回一个负值;

fork出错可能有两种原因:

(1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。(2)系统内存不足,这时errno的值被设置为ENOMEM。(关于errno的意义,请参考本系列的第一篇文章。)

fork系统调用出错的可能性很小,而且如果出错,一般都为第一种错误。如果出现第二种错误,说明系统已经没有可分配的内存,正处于崩溃的边缘,这种情况对Linux来说是很罕见的。

说到这里,聪明的读者可能已经完全看懂剩下的代码了,如果pid小于0,说明出现了错误;pid==0,就说明fork返回了0,也就说明当前进程是子进程,就去执行printf("I am the child!"),否则(else),当前进程就是父进程,执行printf("I am the parent!")。完美主义者会觉得这很冗余,因为两个进程里都各有一条它们永远执行不到的语句。不必过于为此耿耿于怀,毕竟很多年以前,UNIX的鼻祖们在当时内存小得无法想象的计算机上就是这样写程序的,以我们如今的"海量"内存,完全可以把这几个字节的顾虑抛到九霄云外。

说到这里,可能有些读者还有疑问:如果fork后子进程和父进程几乎完全一样,而系统中产生新进程唯一的方法就是fork,那岂不是系统中所有的进程都要一模一样吗?那我们要执行新的应用程序时候怎么办呢?从对Linux系统的经验中,我们知道这种问题并不存在。至于采用了什么方法,我们把这个问题留到后面具体讨论。

exit

在2.4.4版内核中,exit是第1号调用,其在Linux函数库中的原型是:

#includestdlib.h

void exit(int status);

不像fork那么难理解,从exit的名字就能看出,这个系统调用是用来终止一个进程的。无论在程序中的什么位置,只要执行到exit系统调用,进程就会停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。请看下面的程序:

/* exit_test1.c */

#includestdlib.h

main()

{

printf("this process will exit!

");

exit(0);

printf("never be displayed!

");

}

编译后运行:

$gcc exit_test1.c -o exit_test1

$./exit_test1

this process will exit!

我们可以看到,程序并没有打印后面的"never be displayed! ",因为在此之前,在执行到exit(0)时,进程就已经终止了。

exit系统调用带有一个整数类型的参数status,我们可以利用这个参数传递进程结束时的状态,比如说,该进程是正常结束的,还是出现某种意外而结束的,一般来说,0表示没有意外的正常结束;其他的数值表示出现了错误,进程非正常结束。我们在实际编程时,可以用wait系统调用接收子进程的返回值,从而针对不同的情况进行不同的处理。关于wait的详细情况,我们将在以后的篇幅中进行介绍。

exit和_exit

作为系统调用而言,_exit和exit是一对孪生兄弟,它们究竟相似到什么程度,我们可以从Linux的源码中找到答案:

#define __NR__exit __NR_exit /* 摘自文件include/asm-i386/unistd.h第334行 */

"__NR_"是在Linux的源码中为每个系统调用加上的前缀,请注意第一个exit前有2条下划线,第二个exit前只有1条下划线。

这时随便一个懂得C语言并且头脑清醒的人都会说,_exit和exit没有任何区别,但我们还要讲一下这两者之间的区别,这种区别主要体现在它们在函数库中的定义。_exit在Linux函数库中的原型是:

#includeunistd.h

void _exit(int status);

和exit比较一下,exit()函数定义在stdlib.h中,而_exit()定义在unistd.h中,从名字上看,stdlib.h似乎比unistd.h高级一点,那么,它们之间到底有什么区别呢?让我们先来看流程图,通过下图,我们会对这两个系统调用的执行过程产生一个较为直观的认识。

从图中可以看出,_exit()函数的作用最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序,也是因为这个原因,有些人认为exit已经不能算是纯粹的系统调用。

exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是图中的"清理I/O缓冲"一项。

在Linux的标准函数库中,有一套称作"高级I/O"的函数,我们熟知的printf()、fopen()、fread()、fwrite()都在此列,它们也被称作"缓冲I/O(buffered I/O)",其特征是对应每一个打开的文件,在内存中都有一片缓冲区,每次读文件时,会多读出若干条记录,这样下次读文件时就可以直接从内存的缓冲区中读取,每次写文件的时候,也仅仅是写入内存中的缓冲区,等满足了一定的条件(达到一定数量,或遇到特定字符,如换行符和文件结束符EOF),再将缓冲区中的内容一次性写入文件,这样就大大增加了文件读写的速度,但也为我们编程带来了一点点麻烦。如果有一些数据,我们认为已经写入了文件,实际上因为没有满足特定的条件,它们还只是保存在缓冲区内,这时我们用_exit()函数直接将进程关闭,缓冲区中的数据就会丢失,反之,如果想保证数据的完整性,就一定要使用exit()函数。

请看以下例程:

/* exit2.c */

#includestdlib.h

main()

{

printf("output begin

");

printf("content in buffer");

exit(0);

}

编译并运行:

$gcc exit2.c -o exit2

$./exit2

output begin

content in buffer

/* _exit1.c */

#includeunistd.h

main()

{

printf("output begin

");

printf("content in buffer");

_exit(0);

}

编译并运行:

$gcc _exit1.c -o _exit1

$./_exit1

output begin

在Linux中,标准输入和标准输出都是作为文件处理的,虽然是一类特殊的文件,但从程序员的角度来看,它们和硬盘上存储数据的普通文件并没有任何区别。与所有其他文件一样,它们在打开后也有自己的缓冲区。

请读者结合前面的叙述,思考一下为什么这两个程序会得出不同的结果。相信如果您理解了我前面所讲的内容,会很容易的得出结论。

在这篇文章中,我们对Linux的进程管理作了初步的了解,并在此基础上学习了getpid、fork、exit和_exit四个系统调用。在下一篇文章中,我们将学习与Linux进程管理相关的其他系统调用,并将作一些更深入的探讨。

前面的文章中,我们已经了解了父进程和子进程的概念,并已经掌握了系统调用exit的用法,但可能很少有人意识到,在一个进程调用了exit之后,该进程并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构。在Linux进程的5种状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。从这点来看,僵尸进程虽然有一个很酷的名字,但它的影响力远远抵不上那些真正的僵尸兄弟,真正的僵尸总能令人感到恐怖,而僵尸进程却除了留下一些供人凭吊的信息,对系统毫无作用。

也许读者们还对这个新概念比较好奇,那就让我们来看一眼Linux里的僵尸进程究竟长什么样子。

当一个进程已退出,但其父进程还没有调用系统调用wait(稍后介绍)对其进行收集之前的这段时间里,它会一直保持僵尸状态,利用这个特点,我们来写一个简单的小程序:

/* zombie.c */

#include

#include

main()

{

pid_t pid;

pid=fork();

if(pid0) /* 如果出错 */

printf("error occurred!n");

else if(pid==0) /* 如果是子进程 */

exit(0);

else /* 如果是父进程 */

sleep(60); /* 休眠60秒,这段时间里,父进程什么也干不了 */

wait(NULL); /* 收集僵尸进程 */

}

sleep的作用是让进程休眠指定的秒数,在这60秒内,子进程已经退出,而父进程正忙着睡觉,不可能对它进行收集,这样,我们就能保持子进程60秒的僵尸状态。

编译这个程序:

$ cc zombie.c -o zombie

后台运行程序,以使我们能够执行下一条命令:

$ ./zombie

[1] 1577

列一下系统内的进程:

$ ps -ax

... ...

1177 pts/0 S 0:00 -bash

1577 pts/0 S 0:00 ./zombie

1578 pts/0 Z 0:00 [zombie ]

1579 pts/0 R 0:00 ps -ax

看到中间的"Z"了吗?那就是僵尸进程的标志,它表示1578号进程现在就是一个僵尸进程。

我们已经学习了系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁。僵尸进程虽然对其他进程几乎没有什么影响,不占用CPU时间,消耗的内存也几乎可以忽略不计,但有它在那里呆着,还是让人觉得心里很不舒服。而且Linux系统中进程数目是有限制的,在一些特殊的情况下,如果存在太多的僵尸进程,也会影响到新进程的产生。那么,我们该如何来消灭这些僵尸进程呢?

先来了解一下僵尸进程的来由,我们知道,Linux和UNIX总有着剪不断理还乱的亲缘关系,僵尸进程的概念也是从UNIX上继承来的,而UNIX的先驱们设计这个东西并非是因为闲来无聊想烦烦其他的程序员。僵尸进程中保存着很多对程序员和系统管理员非常重要的信息,首先,这个进程是怎么死亡的?是正常退出呢,还是出现了错误,还是被其它进程强迫退出的?其次,这个进程占用的总系统CPU时间和总用户CPU时间分别是多少?发生页错误的数目和收到信号的数目。这些信息都被存储在僵尸进程中,试想如果没有僵尸进程,进程一退出,所有与之相关的信息都立刻归于无形,而此时程序员或系统管理员需要用到,就只好干瞪眼了。

那么,我们如何收集这些信息,并终结这些僵尸进程呢?就要靠我们下面要讲到的waitpid调用和wait调用。这两者的作用都是收集僵尸进程留下的信息,同时使这个进程彻底消失。下面就对这两个调用分别作详细介绍。

c语言 在一个线程上开辟一段内存;

这个不是C语言能做的,因为有“类”。

基本实现思路和@fengfei5551223 类似

提出一些不同的实现细节:

1、申请空间为了做到最大化兼容,使用void指针;size是具体的数值

void * buf=NULL;

void create_memory(){

buf=(void *) malloc(size);//

}

2、你的要求是开辟内存,写内存,读内存,那么应该是操作的同一块内存区域,

因此传参数不能总是调用create_memory方法,否则每次总是新申请内存,

没有达到共用的目的

class A{

char *buf=NULL

public:

//增加一个获取开辟空间地址函数

void *get_buf(){

return buf;

}

};

int main(){

A *a;

pthread_create(a[0],NULL,a-create_memory,NULL);

if(NULL != a-get_buf()){ // 为了保证开辟成功内存

//将开辟好的空间地址作为参数传递给其它线程使用

pthread_create(a[1],NULL,a-write_memory,a-get_buf());

pthread_create(a[2],NULL,a-read_memory,a-get_buf());

}

。。。

}

3、对开辟出的内存区域没有最终销毁这个是很危险的,

当然我不清楚你的需求,但是大多数场景下还有最后一步是做destory;

而且要用到同步互斥变量,所以最后需要报这些变量销毁;

这样使得程序更具有健壮性。

Linux C函数Kill

你是程序中调用kill函数,还是在命令行调用kill命令?

int kill(pid_t pid, int sig); 函数有两个参数,一个是进程号,一个是信号

如果你输入的进程号是正确的,而进程还在,则信号有可能被该进程忽略了,不知道你发送的信号是几号? 只有SIGKILL SIGSTOP不能被忽略,其它都可以忽略或捕捉。


推荐阅读
  • 我创建了一个新的AWSSSO(使用内部IDP作为身份源,因此不使用ActiveDirectory)。我能够登录AWSCLI、AWSGUI,但 ... [详细]
  • Linux学习笔记:psef、ps aux、kill9
    一、查看进程命令1.ps命令Linux中的ps命令是ProcessStatus的缩写。ps命令用来列出系统中当前运行的那些进程。ps命令列出的是当前那些进程的快照,就 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的步骤和方法
    本文介绍了在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的详细步骤和方法。首先需要下载最新的Java SE Development Kit 9发行版,然后按照给出的Shell命令行方式进行安装。详细的步骤和方法请参考正文内容。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 本文介绍了在RHEL 7中的系统日志管理和网络管理。系统日志管理包括rsyslog和systemd-journal两种日志服务,分别介绍了它们的特点、配置文件和日志查询方式。网络管理主要介绍了使用nmcli命令查看和配置网络接口的方法,包括查看网卡信息、添加、修改和删除配置文件等操作。 ... [详细]
  • 在单位的一台4cpu的服务器上部署了esxserver,挂载了6个虚拟机,目前运行正常。在安装部署过程中,得到了cnvz.net论坛精华区 ... [详细]
  • 现在需要用到php(现在可以用)
    本文目录一览:1、现在在工作中PHP用到的多么? ... [详细]
  • 小编这次要给大家分享的是详解Python定时任务APScheduler,文章内容丰富,感兴趣的小伙伴可以来了解一下,希望大家阅读完这篇文章之后能够有所收获 ... [详细]
  • Linux运维 第五阶段 puppet基础
    一、相关概念:1、puppet基于CS架构,使用ruby编写,在类UNIX平台上集中配置管理系统,它可以管理配置文件、用户、 ... [详细]
  • CentOS下基于PPTPD与AD验证的×××服务器构建
    一.服务器加入AD域名1.安装kerberos、samba、ntpdateyum-yinstallkrb5-workstationpam_krb5krb5-develkrb5-li ... [详细]
author-avatar
躲避世界2502862687
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有