【Linux】进程间关系

版权声明:本文为博主原创文章,未经博主允许不得转载。Copyright (c) 2018, code farmer from sust. All rights reserved. https://blog.csdn.net/sustzc/article/details/82734498

进程组
    进程组就是作业,作业就是进程组。
    只要在某个进程组中有一个进程存在,则该进程组就存在,这与其组长进程(进程组中的第一个进程)是否终止无关。
        eg:sleep 100 | sleep 200 | sleep 300 &
        加上&表示后台运行,不加表示前台运行,也就是在终端上运行。
        在前台运行上述命令时,按下ctrl+c,终止的是整个进程组,而不是某一个进程。
        在后台运行上述命令时,按下ctrl+c,没有反应,需要用killall或者kill命令来杀死进程或进程组。
        前台->后台:ctrl+z   后台->前台:fg [job号]  查看后台进程状态: jobs
    kill -9 杀掉进程组长,但是进程组还在。
        ps axj | grep sleep | grep -v sleep
        ps选项:
            a: 不仅列出当前用户的进程,也列出所有其他用户的进程。
            x: 表示不仅列出有控制终端的进程,也列出所有无控制终端的进程。
            j: 表示列出与作业控制相关的信息。
    
作业
    shell分前后台来控制的不是进程,而是作业(job)或者进程组,shell可以运行一个前台作业和任意多个后台作业,这称为作业控制。
    作业和进程组的区别:如果作业中的某个进程又创建了子进程,则该子进程不属于作业。
    一旦作业运行结束,shell就把自己提到前台(子进程还在,可是子进程不属于作业),如果原来的前台进程还存在
(如果这个子进程还没终止),它自动变为后台进程组。
    在前台新起作业,shell是无法运行的,因为他被提到了后台。 但是如果前台进程退出,shell就又被提到了前台,
所以可以继续接受用户输入。

会话
    会话(session)是一个或多个进程组的集合,一个会话可以有一个控制终端。这通常是登陆到其上的终端
设备(在终端登陆情况下)或伪终端设备(在网络登陆情况下)。建立与控制终端连接的会话首进程被称为
控制进程。一个会话中的几个进程组可被分为一个前台进程组以及一个或多个后台进程组。所以一个会话
中,应该包括控制进程(会话首进程),一个前台进程组和任意后台进程组。
    首进程就是bash,一个会话不一定有一个终端,(?)。
    ps axj | head -n1 查看表头,其中SID表示会话id。
    每打开一个终端,就新建了一个会话。
    tty查看当前终端信息,eg: echo "hello" > /dev/pts/0   (重定向到想要输出的终端)
    线路规程:处理键盘输入信息,若为字符,则显示,若不为字符,则交给OS处理即可。
    
作业控制(前后台作业)
    文件传输协议:ftp
    telnet测试网络端口是否畅通  telnet www.baidu.com 80
    telnet命令用于登录远程主机,对远程主机进行管理。telnet因为采用明文传送报文,安全性不好,很多Linux服务器都不开放telnet服务。
    选项
        -a尝试自动登录远程主机
    windows中的服务程序在电脑->管理      (删除不常用的服务程序,服务越多,被攻击的可能性就越大。)

    Linux下的服务,我们称为守护进程(Daemon)或者叫做精灵进程,是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行
某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程实现的,比如ftp,ssh等等。

    系统服务进程(守护进程)不受用户登录注销的影响,它们一直在运行着。这种进程有一个名称叫守护进程(Daemon)。
    ps axj
    凡是TPGID一栏写着-1的都是没有控制终端的进程,也就是守护进程。在COMMAND一列用[]括起来的名字表示内核线程,
这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行, 通常采用以k开头的名字,表示Kernel。
init进程我们已经很熟悉了,udevd负责维护/dev目录下的设备文件,acpid负责电源管理,syslogd负责维护/var/log下的日志文件。
    可以看出,守护进程通常采用以d结尾的名字,表示Daemon。
    特点:
        1.后台运行;
        2.脱离终端会话。

创建守护进程

创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为session leader。
#include <unistd.h>
// 设置会话id
pid_t setsid(void);
    返回值:该函数调用成功时返回新创建的Session的id(其实也就是当前进程id),失败返回-1。
    注意:调用这个函数之前,当前进程不允许是进程组的Leader,否则返回-1。要保证当前进程不是进程组的leader,
只需要先fork出一个子进程(父进程exit)再调用setsid就行了。
    成功调用该函数的结果:
    1.创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。
    2.创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。
    3.如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失
去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是一个普通的打开文件而不是控制终端了。

    umask(0);  // 产生文件的预设权限
    
    1.创建fork子进程,父进程exit;
    2.启动一个新的会话 setsid;
    3.关闭文件描述符表中的0 1 2;
        1> for (int i = 0; i < 255; i++) { close(i); }   // 如果打开了某个文件则关闭,如果没打开则报错。
        2> dup到/dev/null中     /dev/null是个空洞文件,相当于垃圾回收站。
    4.将当前路径改为根路径;(防止卸载不掉某些u盘)
    5.执行的动作。
    
    eg:
        close(0);
        dup2(fd, 1);
        dup2(fd, 2);
        
模拟crontab,实现定期扫描shell命令并去执行。(windows中的计划任务,linux下是crond)
    #include <unistd.h>
    int daemon(int nochdir, int noclose);

    setup可以查看系统的服务程序。
    tail -f tmp 追加打印

    int chdir(const char *path);
    更改当前路径为根路径,这样管理员就可以卸载掉这部分文件。
        chdir("/");
    char *getcwd(char *buf, size_t size); // 获取当前进程的工作路径
    /proc/self下的进程信息
    ssize_t readlink(const char *pathname, char *buf, size_t bufsize); // 获取软链接对应的可执行程序

// 调用守护进程
#include <unistd.h>
int daemon(int nochdir, int noclose);
参数:如果nochdir为0,那么会把当前路径改为根路径,如果非0,那么不会修改。
    如果noclose为0,那么会将0 1 2这些标准输入输出出错的文件重定向到/dev/null中,如果非0,则不会关闭0 1 2。
    
    ls /dev/   查看终端

猜你喜欢

转载自blog.csdn.net/sustzc/article/details/82734498