IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux系统编程-进程 -> 正文阅读

[系统运维]Linux系统编程-进程

进程

  1. 进程标识符PID
  2. 父子进程的产生
    fork()、vfork()
  3. 进程的消亡及资源释放
  4. exec函数族
  5. 用户权限及组权限
  6. 观摩:什么是解释器文件
  7. system()函数
  8. 进程会计
  9. 进程时间
  10. 守护进程
  11. 系统日志

进程PID

类型pid_t,有符号16位整型数
进程号顺序向下使用
命令pd
getpid()
getppid()

进程创建

man fork

NAME
       fork - create a child process //复制当前进程,一模一样,执行到的位置都一样
SYNOPSIS
       #include <sys/types.h>
       #include <unistd.h>
       pid_t fork(void); //
       返回值:
       	成功:在父进程中返回的是子进程的PID,在子进程中返回的是0
       	失败:-1,返回给父进程,并设置errno

duplicating:代码一式两份,一摸一样,除了以下几点:
父子进程的区别:

  1. PID不同,PPID不同
  2. fork()的返回值不同
  3. 未决信号(还没来得及响应的信号)和文件锁不继承
  4. 资源利用量清零
    init进程:所有进程的父进程,PID为1

调度器调度策略,来决定哪个进程先运行。

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char const *argv[]) {
    pid_t pid;
    printf("[%d]Begin!\n",getpid());

    //fflush(NULL); //fork()之前一定要刷新缓冲区,如果不刷新,子进程缓冲区同样会有"[父进程号]:Begin!",从而会导致进程输出重定向至文件时,出现两次“[父进程号]:Begin!”
    //标准输出行缓冲机制,文件全缓冲机制
    pid=fork();

    if (pid<0) {
        perror("fork()");
        exit(1);
    }
    if (pid==0) {
        //子进程
        printf("[%d]:Child is working\n",getpid());
    }else{
        //父进程
        printf("[%d]:Parent is working!\n",getpid());
    }
    printf("[%d]:End!\n",getpid());
}
===================未刷新流=============
lry@ubuntu:~/codes/procrdd$ cat /tmp/out
[2506]Begin!	-------------注意哦
[2507]:Child is working
[2507]:End!
[2506]Begin!	------------注意哦,父进程Begin
[2506]:Parent is working!
[2506]:End!

查看进程树
ps -afx
顶格表示父进程是init进程,此时子进程是孤儿进程

fork()之前一定要刷新缓冲区!!!!fflush()

fork-demo

fork-demo1

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>

#define LEFT  30000000
#define RIGHT 30000200

int main(int argc, char const *argv[]){

    int i=0,j,mark;

    for (i= LEFT; i <= RIGHT; i++) {
        mark=1;
        for (j  = 2; j < i/2; j++) {
            if (i%j==0) {
                mark=0;
                break;
            }
        }
        if (mark) {
            printf("%d is a primer\n",i);
        }
    }

    exit(0);
}

fork-demo2

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>

#define LEFT  30000000
#define RIGHT 30000200

int main(int argc, char const *argv[]){

    int i=0,j,mark;
    pid_t pid;

    for (i= LEFT; i <= RIGHT; i++) {//201次
        pid=fork();//子进程与父进程执行的位置(状态)一样
        if (pid<0)  {
            perror("fork()");
            exit(1);
        }else if(pid==0){
            mark=1;
            for (j  = 2; j < i/2; j++) {
                if (i%j==0) {
                    mark=0;
                    break;
                }   
            }
            if (mark) {
                printf("%d is a primer\n",i);
            }
            exit(0);  
        }        
    }
    exit(0);
}

时间统计

lry@ubuntu:~/codes/procrdd$ time ./getprime > /dev/null

real    0m0.789s
user    0m0.784s
sys     0m0.004s
lry@ubuntu:~/codes/procrdd$ time ./getprime2 > /dev/null

real    0m0.070s
user    0m0.000s
sys     0m0.012s

谁打开谁关闭,谁申请谁释放
父进程给子进程收尸,否组子进程会成为僵尸进程
僵尸态:应该是一闪而过,若操作系统或父进程比较忙,僵尸状态可能会持续一会,
僵尸进程会浪费PID

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>

#define LEFT  30000000
#define RIGHT 30000200

int main(int argc, char const *argv[]){

    int i=0,j,mark;
    pid_t pid;

    for (i= LEFT; i <= RIGHT; i++) {//201次

        pid=fork();//子进程与父进程执行的位置(状态)一样
        if (pid<0)
        {
            perror("fork()");
            exit(1);
        }else if(pid==0){
            //printf("我正在找素数,我的PID:%d",getpid());
            mark=1;
            for (j  = 2; j < i/2; j++) {
                if (i%j==0) {
                    mark=0;
                    break;
                }
            }
            if (mark) {
                printf("%d is a primer\n",i);
            }
           // sleep(1000); //子进程执行完直接退出,子进程没有人收尸,于是便成为了僵尸进程
            exit(0);
        }
    }//谁打开谁关闭,谁申请谁释放
    sleep(1000); //父进程睡眠态
    exit(0);
}

父进程创建完子进程后sleep(1000),子进程执行完之后因无人收尸变成僵尸进程,父进程醒后直接退出,子进程变成孤儿进程,挂靠init进程

vfork

fork

写时拷贝
父子进程,谁写谁拷贝,写的时候才拷贝

进程的消亡及资源释放

5个正常终止,3个异常终止

wait()
waitpid()

waitid()
wait3()
wait4()

man 2 wait

NAME
       wait, waitpid, waitid - wait for process to change state //等待进程状态发生变化

SYNOPSIS
       #include <sys/types.h>
       #include <sys/wait.h>

       pid_t wait(int *wstatus); //把当前子进程收尸收回来的状态放到wstatus中
       参数:wstatus 进程状态存储的地址
       返回值:pid_t
      	 	成功:已终止的子进程的pid
      	 	失败:-1

       pid_t waitpid(pid_t pid, int *wstatus, int options);

       int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

	WIFEXITED(status)	返回true,如果正常退出:exit() / _exit() / return /
	WEXITSTASTUS(status)	只有WIFEXITED返回true,才能调用这个函数。返回子进程的退出码
	
	WIFSIGNALED(status) 如果子进程被信号终止,那么返回true
	WTREMSIG(status)	返回导致子进程结束的信号的编号,只有WIFSIGNALED返回true才能调用
	WCOREDUPM(status)	如果子进程产生了core文件,返回true,只有WIFSIGNALED返回true才能调用
       pid_t waitpid(pid_t pid, int *wstatus, int options);
       参数:
       		pid,
       			< -1,给任一子进程收尸,进程组ID为pid绝对值的进程组
       			= 0,给进程自己的任一子进程收尸,进程组ID,等于当前进程的进程组ID,同组ID子进程
       			> 0,给指定pid进程收尸
       		wstatus,
       		option
       			WNOHANG	立即返回,如果子进程没有退出(阻塞-->非阻塞)
       		

wait()的封装:waitpid(-1, &wstatus, 0);

待计算	进程数
201  -->   201
201  -->   N	找N个子进程进行计算

方法①:分块法
	进程1:[1-67]
	进程2:[68-135]
	进程3:[136-201]
方法②:交叉分配法
	有一个进程永远拿不到素数,N的倍数那个
方法③:池内算法

分块法
交叉分配法

exec函数族

FEW:fork、exec、wait
同样需要注意刷新流fflush()

NAME
       execl, execlp, execle, execv, execvp, execvpe - execute a file //运行一个二进制可执行文件
       The  exec()  family  of  functions replaces the current process image with a new process image.
       替换进程映像

SYNOPSIS
       #include <unistd.h>
       extern char **environ;
       int execl(const char *pathname, const char *arg, ... /* (char  *) NULL */);
       int execlp(const char *file, const char *arg, .../* (char  *) NULL */);
       int execle(const char *pathname, const char *arg, ... /*, (char *) NULL, char *const envp[] */);
       int execv(const char *pathname, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[], char *const envp[]);
		
		返回值:如果有返回值,则表示出错了
					返回值是-1,设置errno

示例:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(int argc, char const *argv[])
{
    pid_t pid;

    puts("Begin!");
    fflush(NULL);
    pid=fork();
    if (pid<0)
    {
        perror("fork()");
        exit(1);
    }
    if (pid==0)
    {
        execl("/bin/date","date","+%s",NULL); //木马可伪装称date
        perror("execl()");
        exit(1);
    }

    wait(NULL);
    puts("End!");
    exit(0);
}

文件描述符继承:
在这里插入图片描述
外部命令:能够在磁盘上找到二进制可执行文件的命令
内部命令:
外部命令实现:

myshell 命令实现
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <glob.h>
#define DELIMS " \t\n"

struct cmd_st
{
    glob_t globres;
};

static void prompt(void){
    printf("mysh-0.0.1$ ");
}

static void parse(char *line,struct cmd_st *res){
    char *tok;
    int i=0;
    while (1)
    {
        tok=strsep(&line,DELIMS);
        if(tok==NULL) 
            break;
        if(tok[0]=='\0')
            continue;
        glob(tok,GLOB_NOCHECK|GLOB_APPEND*i,NULL,&res->globres);
        i=1;
    }    
}

int main(int argc, char const *argv[])
{
    /**
     * 1. 打印命令提示符
     * 2. 获取输入的命令
     * 3. 解析得到的命令
     * 4. 判断外部、内部命令
     *      如果是内部命令,什么也不做
     *      如果是外部命令,
     *          fork();
     *          子进程执行execl
     *          父进程wait收尸
     **/

    char *linebuf=NULL;
    size_t linebuf_size=0;
    struct cmd_st cmd;
    pid_t pid;
 
    while (1)
    {
        prompt();
        if(getline(&linebuf,&linebuf_size,stdin)<0)
            break;
        parse(linebuf,&cmd);
        if (0)
        {
            //暂不处理内部命令
        }else{
            pid=fork();
            if (pid<0)
            {
                perror("fork()");
                exit(1);
            }
            if (pid==0)
            {
                execvp(cmd.globres.gl_pathv[0],cmd.globres.gl_pathv);
                perror("execvp()");
                exit(1);
            }else{
                wait(NULL);//父进程
            }
        }           
    }
    exit(0);
}

UNIX–三个函数few组成

用户权限和组权限

执行命令的时候带着执行者的身份。
u+s,如果一个可执行文件有u+s权限,那么当其他用户执行这个可执行文件的时候,该用户会切换成这个可执行文件的user身份,然后再执行
g+s,同理u+s
u+s和g+s用来将root权限下放。

UID:
存储了三份:
real 真实的
effective 有效的,鉴定权限看的是effective
save(可以没有save)

GID
在这里插入图片描述
exec来鉴定权限

lry@ubuntu:~/codes$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 Jul 15 06:08 /usr/bin/passwd
	's': 保存当前文件是否有u+s、 g+s的权限

用户权限

常用函数

getuid()
geteuid()
getgid()
getegid()
setuid()
setgid() 设置effective gid
setreuid() 交换ruid和euid
setregid() 交换rgid和egid
seteuid()
setegid()

脚本文件,解释器文件

#!+解释器
#!/bin/bash看到脚本文件标记,直接把/bin/bash装载进来
解释器:

可以修改登录的shell为/usr/bin/top

system()函数

fork、exec*、wait的简单封装

man system

NAME
       system - execute a shell command
SYNOPSIS
       #include <stdlib.h>
       int system(const char *command);

进程会计

略。
man 5 acct
不可移植

进程时间

man 2 times

AME
       times - get process times

SYNOPSIS
       #include <sys/times.h>

       clock_t times(struct tms *buf);

DESCRIPTION
       times() stores the current process times in the struct tms that buf points to.  The struct tms is as
       defined in <sys/times.h>:

           struct tms {
               clock_t tms_utime;  /* user time */
               clock_t tms_stime;  /* system time */
               clock_t tms_cutime; /* user time of children */
               clock_t tms_cstime; /* system time of children */
           };

守护进程

  1. 脱离控制终端
  2. 一般是会话leader,进程组leader

会话 session,标识sid
终端(虚拟终端)

最多只有一个前台进程组,可以没有前台进程组,前台进程组能够接收标准输入或者进行标准输出。
后台进程组则不可以,如果试图将标准输入的内容发送给后台进程,那么将会导致后台进程退出。后台进程需要重定向IO
在这里插入图片描述

重要函数setsid



NAME
       setsid - creates a session and sets the process group ID

SYNOPSIS
       #include <sys/types.h>
       #include <unistd.h>

       pid_t setsid(void);

ps -axj
PPID PID PGID SID TTY
PPID为1,PID=PGID=SID,TTY=?的进程,就是守护进程

lry@ubuntu:~/codes/procrdd$ ps -axj
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
      1   32558   32558   32558 ?             -1 Ss       0   0:00 /sbin/iscsid
      1   32559   32559   32559 ?             -1 S<Ls     0   0:00 /sbin/iscsid

函数getpgrp()

man getpgrp
NAME
       setpgid, getpgid, setpgrp, getpgrp - set/get process group

SYNOPSIS
       #include <sys/types.h>
       #include <unistd.h>

       int setpgid(pid_t pid, pid_t pgid);  把pid进程放到进程组pgid
       pid_t getpgid(pid_t pid);	//获取进程的进程组ID

       pid_t getpgrp(void);                 /* POSIX.1 version */
       pid_t getpgrp(pid_t pid);            /* BSD version */

       int setpgrp(void);                   /* System V version */
       int setpgrp(pid_t pid, pid_t pgid);  /* BSD version */

守护进程实例

系统日志

/var/log
系统主日志文件/etc/log/messages
syslogd服务
man openlog

NAME
       closelog, openlog, syslog, vsyslog - send messages to the system logger

SYNOPSIS
       #include <syslog.h>

       void openlog(const char *ident, int option, int facility);
       参数:
       		ident, 人物
       		option,选项
       		facility, 消息来源
       void syslog(int priority, const char *format, ...);
       参数:
       		priority,日志级别
       void closelog(void);

配置文件:/etc/sys

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
#define FNAME "/tmp/out"

static int daemonize(void) {
    int fd;
    pid_t pid;
    pid = fork();
    if (pid < 0) {
        //perror("fork()");
        return -1;
    }
    if (pid > 0) {
        exit(0);
    }
    fd = open("/dev/null", O_RDWR);
    if (fd < 0) {
        //perror("open");
        return -1;
    }
    dup2(fd, 0);
    dup2(fd, 1);
    dup2(fd, 2);
    if (fd > 2) {
        close(fd);
    }
    setsid();
    chdir("/");
    umask(0);
    return 0;
}
#define FNAME "/tmp/out"
int main(int argc, char const *argv[]) {
    FILE *fp;
    int i = 0;
    openlog("mydaemon",LOG_PID,LOG_DAEMON);
    if (daemonize()) {
        syslog(LOG_ERR,"daemonize() has failed!");
        exit(1);
    }else {
        syslog(LOG_INFO,"daemonize() has succeeded");
    };
    fp = fopen(FNAME, "w");
    if (fp == NULL) {
        // perror("fopen()");
        syslog(LOG_ERR,"fopen():%s",strerror(errno));
        exit(1);
    }
    syslog(LOG_INFO,"%s has been opened.",FNAME);
    for (i = 0;; i++) {
        fprintf(fp, "%d\n", i);
        fflush(fp);
        syslog(LOG_DEBUG,"%d printed.",i);
        sleep(1);
    }
    fclose(fp); //执行不到
    closelog(); //执行不到
    exit(0);
}

单实例的守护进程

使用锁文件来实现/var/run/name.pid
开机启动脚本文件/etc/rc*

lry@ubuntu:/var/run$ cat /etc/rc.d/rc.local
#!/bin/bash
# secu-tcs-agent bootstart, install at Sun 03 Oct 2021 12:57:11 PM CST
/usr/local/sa/agent/secu-tcs-agent-mon-safe.sh > /dev/null 2>&1
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-10-04 13:11:34  更:2021-10-04 13:13:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 18:20:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码