目录

目录 1

1. 名词解释 1

2. 什么是守护进程? 2

2.1. 后台运行 2

2.2. 解释关系 2

3. 以“&”方式运行有何问题? 2

4. fork 2

5. setsid&setuid 3

5.1. setuid应用场景 3

5.2. 案例 3

5.3. 用户ID 4

5.4. chmod 5

6. fg&bg 6

7. abc.cpp 7

1. 名词解释

名词(中文)

名词(英文)

解释

会话

Session

每打开一次终端(本地或远程)登录Linux,都会生成一个新的会话;除此之外,程序中也可以调用函数setsid创建一个新的会话;脚本也可以调用命令setsid创建一个新的会话。新建的会话无控制终端。

会话ID

SessionID

用来标识一个会话,同一时刻不同会话的ID不会相同,是一个int类型的整数值。

用户

User

指能登录Linux的用户帐号

用户ID

UserID

用来唯一标识一个用户

伪终端或叫虚拟终端

pty

(Pseudo Terminal)

控制终端

tty

(Teletypewriter或Teletype)

字符型设备

pts

(pseudo-terminal slave)

pty的实现方法,分两端:一端叫master,另一端叫slave。可打开的最多pts数为/proc/sys/kernel/pty/max,当前已打开的pts数为/proc/sys/kernel/pty/nr。

2. 什么是守护进程?

在后台运行的进程不一定是守护进程!一个进程要成为守护进程,必须做到以下两点:

1) 在后台运行

2) 脱离了终端

2.1. 后台运行

要使一个进程在后台运行,代码中可以通过fork子进程来实现,而命令行或脚本中可以通过使用“&”来实现。

fork之后,子进程会继承父进程的SessionID,调用execve()后的进程的SessionID不会改变。

2.2. 解释关系

子进程从父进程继承了:SessionID、进程组ID和打开的终端。子进程如果要脱离这些,代码中可通过调用setsid来实现。,而命令行或脚本中可以通过使用命令setsid来运行程序实现。setsid帮助一个进程脱离从父进程继承而来的已打开的终端、隶属进程组和隶属的会话。

需要注意,代码中调用setsid是有条件的:即调用进程自己不能是进程组长。因此,调用setsid之前需要先fork,然后由产生的子进程调用setsid。

3. 以“&”方式运行有何问题?

以“&”方式可以将一个前台进程以后台方式运行,但是如果它是一个终端的job,则如果向终端收到SIGHUP信号,终端也会向它的所有job发送SIGHUP,这样以“&”方式运行的进程则会因为收到SIGHUP则退出。

当用户注销(logout)或者网络断开时,终端会收到 SIGHUP(hangup)信号从而关闭其所有子进程。

早期的Unix,终端通过Modem和系统通讯,当用户注销(logout)时,Modem就会挂断(hangup)电话;当Modem断开时,会给终端发SIGHUP来通知终端关闭所有子进程。

4. fork

fork只是使得进程可以以后台方式运行,但不能使进程完全独立,因为fork出来的进程仍然继承了父进程已打开的终端、会话和进程组。

5. setsid&setuid

setsid命令或函数

setuid函数(相对应的命令为chmod)

1) 创建一个会话

2) 调用进程将成为会话的组长

3) 调用进程将成为进程组的组长

4) 调用进程将脱离控制终端(tty)

5) 会话ID和进程组ID都和调用进程的PID相同

1) 设置调用进程的真实用户ID、有效用户ID和保存用户ID

按下“ctrl+z”会触发SIGTSTP,注意不是SIGSTOP,这两个信号的区别是前者可以捕获,而后者不可以。进程收到这两个信号后,都进入STOP状态,使用ps aux看到的状态值为“T”,可以通过发送信号SIGCONT重新回到运行状态。

5.1. setuid应用场景

1) 以root启动,但以其它用户身份运行,常见于Webserver,因为需要监听80端口,不得不以root启动,但root权限过大,因此运行经常会从root切换到nobody等用户;

2) 开发中经常需要让非root用户能够去gdb一些root启动的进程,这个时候只开放gdb等少数一些命令给非root用户。

5.2. 案例

使用ls命令查看下passwd:

~> ls -l /usr/bin/passwd

-rwsr-xr-x 1 root shadow 73300 2007-05-04 19:30 /usr/bin/passwd

~> ls -l /etc/passwd

-rw-r--r-- 1 root root 1138 2015-03-31 17:04 /etc/passwd

从上可以看到,虽然所有用户对/usr/bin/passwd都有可执行权限,但只有root对/etc/passwd有可修改权限。使用/usr/bin/passwd修改密码时,/usr/bin/passwd会修改/etc/passwd,为何普通用户也可以执行passwd修改密码了?

这里的奥秘就在/usr/bin/passwd的权限属性,不难看到/usr/bin/passwd隶属用户为root,对root的权限为“rws”,这里不是“rwx”而是“s”。

这个“s”表示,当其它用户执行时,用效用户将变成root,因此普通用户才可以修改密码。如果将“s”变成“x”,则普通用户将不能修改密码。

请观察:

# ls -l /usr/bin/passwd

-rwsr-xr-x 1 root shadow 73300 May  4  2007 /usr/bin/passwd

# chmod u-s /usr/bin/passwd

# ls -l /usr/bin/passwd

-rwxr-xr-x 1 root shadow 73300 May  4  2007 /usr/bin/passwd

从上面的变化可以看到:权限“s”退化成了“x”。

> whoami

zhangsan

> passwd

Changing password for zhangsan.

Old Password:

Old Password:

passwd: Authentication failure

“s”总是要建立在“x”之上,如果要为一个没有“x”权限的文件添加“s”,则小写“s”会变成大写“S”:

# ls -l abc.log

-rw-r--r-- 1 root root 7 2015-04-22 18:34 abc.log

# chmod u+s abc.log

# ls -l abc.log

-rwSr--r-- 1 root root 7 2015-04-22 18:34 abc.log

# ls -l abc

-rwxr-xr-x 1 root root 35893 2015-04-23 09:40 abc

# chmod u+s abc

# ls -l abc

-rwsr-xr-x 1 root root 35893 2015-04-23 09:40 abc

5.3. 用户ID

真实用户ID

登录(login)时的用户ID

用效用户ID

运行时产生作用的用户ID,比如对于“passwd”命令,以非root用户运行它,但有效用户ID是root的ID。为弄明白,先查看下passwd的文件权限:

# ls -l `which passwd`

-rwsr-xr-x 1 root shadow 79336 2007-05-04 19:29 /usr/bin/passwd

不难看出,passwd有“rwx”之外的另一个权限属性“s”。可借助chmod命令为需要的文件添加“s”权限,如:chmod u+s abc.cpp。

保存的用户ID

看一小段代码:

// filename: uid.cpp

// g++ -g -o uid uid.cpp

#include <stdio.h>

#include <unistd.h>

int main()

{

printf("uid = %d\n", getuid());

printf("effective uid = %d\n", geteuid());

return 0;

}

以root用户编译生成可执行程序uid:

# g++ -g -o uid uid.cpp

# ls -l uid

-rwxr-xr-x 1 root root 10498 2015-04-23 10:43 uid

以用户zhangsan运行uid:

> ./uid

uid = 30038

effective uid = 30038

30038为用户zhangsan的用户ID,以及有效用户ID。以root用户为uid增加“s”权限:

# chmod u+s uid

# ls -l uid

-rwsr-xr-x 1 root root 10498 2015-04-23 10:43 uid

再以用户zhangsan运行uid:

> ./uid

uid = 30038

effective uid = 0

这个时候,有效用户ID不再是30038了,而是变成了0,0是root的用户ID。zhangsan虽然是普通用户,但已获得了root权限。

5.4. chmod

chmod用来修改文件的权限。如果只修改当前用户对文件的权限,可用:chmod u+xrw,这里的“u”表示当前用户自己,如果改成“g”则表示同组,改成“o”则表示其它用户。 示例:

为文件abc添加当前用户可执行权限

chmod u+x abc

为文件abc添加同组用户可读权限

chmod g+r abc

为文件abc添加其它用户可写权限

chmod o+w abc

为文件abc添加当前用户可读可写权限

chmod u+rw abc

为文件abc添加当前用户和同组用户可读可写权限

chmod ug+rw abc

6. fg&bg

看下面一段代码:

// filename: x.cpp

// g++ -g -o x x.cpp

#include <stdio.h>

#include <unistd.h>

int main()

{

while (true)

{

sleep(1);

}

return 0;

}

编译生成可执行程序文件x,然后在终端上执行下列操作:

# jobs

jobs无任何输出,表示没有任何作业

# ./x

从上面的代码可以看出,执行x时,终端会卡住。这个时候按“ctrl+z”,也就是发送SIGTTSTP信号给程序x的进程,进程会被stop,并且进入后台方式:

[1]+  Stopped                 ./x

再执行jobs可以看到:

# jobs

[1]+  Stopped                 ./x

注意,x的父进程必须是终端进程,否则jobs是看不到的。

接下来,执行命令fg:

# fg

./x

会发生x又变成前台进程了,再按“ctrl+z”让它变成后台进程:

[1]+  Stopped                 ./x

执行bg和jobs命令:

# bg

[1]+ ./x &

# jobs

[1]+  Running                 ./x &

这个时候可以看到x变成了一个非stop的,而是running的后台进程。只要x的父进程仍然是终端进程,则仍然可以用命令fg把它调到前台运行。

7. abc.cpp

// filename: abc.cpp

// g++ -g -o abc abc.cpp

#include <fcntl.h>

#include <libgen.h> // basename

#include <pty.h> // openpty and forkpty

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <string>

#include <string.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

// 取得进程程序文件名

static std::string get_process_name(pid_t pid)

{

char process_path[PATH_MAX];

char proc_path[PATH_MAX];

snprintf(proc_path, sizeof(proc_path), "/proc/%d/exe", pid);

readlink(proc_path, process_path, sizeof(process_path)-1);

return basename(process_path);

}

static void info()

{

printf("PID: %d\n", getpid());

printf("ParentPID: %d\n", getppid());

printf("ParentName: %s\n", get_process_name(getppid()).c_str());

printf("GroupID: %d\n", getpgrp());

printf("SessionID: %d\n", getsid(getpid()));

printf("TerminalName: %s\n", ttyname(STDIN_FILENO));

printf("PseudoTerminalName: %s\n", ptsname(STDIN_FILENO));

printf("\n");

}

static void set_session()

{

printf("setsid ...\n");

if (-1 == setsid())

{

perror("setsid");

}

else

{

printf("SessionID: %d\n", getsid(getpid()));

}

}

int main()

{

info();

printf("fork ...\n");

pid_t pid = fork();

if (pid > 0)

exit(0);

sleep(1);

info();

set_session();

info();

printf("fork ...\n");

pid = fork();

if (pid > 0)

exit(0);

info();

while (true)

{

sleep(1);

}

return 0;

}

nohup、&、setsid、fork和fg、bg究竟有啥区别?的更多相关文章

  1. [Linux内核]ctrl-z/fg/bg/nohup/setsid/()与&/disown/screen

    转自:https://my.oschina.net/alphajay/blog/65058 My Tips: Ctrl -z    ->   suspend fg           -> ...

  2. Linux 将进程放入后台执行,解决网络,ssh断开导致进程结束(nohup, setsid, &, disown)

    Linux 将进程放入后台执行,解决网络,ssh断开导致进程结束(nohup,  setsid,  &, disown) 1.nohup 命令 我们知道,当用户注销(logout)或者网络断开 ...

  3. linux fg&bg

    [linux fg&bg] Linux 提供了 fg 和 bg 命令,让我们调度正在运行的任务. 假设你发现前台运行的一个程序需要很长的时间,但是需要干其他的事情,你就可以用 Ctrl-Z , ...

  4. linux进程后台运行的几种方法 - nohup/setsid/&

    linux进程后台运行的几种方法 - nohup/setsid/& [转载]   我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务 ...

  5. "=="和 equals 方法究竟有什么区别?

    "=="和 equals 方法究竟有什么区别? ==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同, 要比较两个基本类型的数据或两个引 ...

  6. [百家号]雷电3和USB Type-C究竟有什么区别?

    雷电3和USB Type-C究竟有什么区别? https://baijiahao.baidu.com/s?id=1617271490773519582&wfr=spider&for=p ...

  7. linux 后台运行进程 fg bg ctrl+z nohup

    fg.bg.jobs.&.nohup.ctrl+z.ctrl+c 命令 一.& 加在一个命令的最后,可以把这个命令放到后台执行,如 watch -n 10 sh test.sh &am ...

  8. nohup命令与&区别,jobs,fg,bg,Ctrl-Z、Ctrl-C、Ctrl-D

    &方式: Unix/Linux下一般想让某个程序在后台运行,很多都是使用 & 在程序结尾来让程序自动运行.比如我们要运行mysql在后台:          /usr/local/my ...

  9. Linux运行与控制后台进程的方法:nohup, setsid, &, disown, screen

    我们经常会碰到这样的问题,用ssh登录了远程的Linux服务器,运行了一些耗时较长的任务,结果却由于网络等的不稳定导致任务中途失败.这是由于在用户注销(logout)或者网络断开时,终端会收到 HUP ...

随机推荐

  1. C#细说多线程(上)

    本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个方面介绍多线程的开发.其中委托的BeginInvoke方法以及回调函数最为常用.而 I/O线程可能容易遭 ...

  2. linux Posix 信号量 一

    信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语. linux提供两种信号量,“内核信号量”和“用户态进程信号量”,“用户态信号量”又分为“Posix”,“System V”信号 ...

  3. Android Studio failed to create error code -6解决方法

    起因是AndroidStudio编译太慢,在stackoverflow上找解决方法,创建了个vm选项文件,导致内存不够用 很多中文博客上都千篇一律地说是内存不够,打开安装路径下bin目录下的studi ...

  4. 转转转--oracle 去重并按时间排序取第一条

    select t.* from (select a.*, row_number() over(partition by 需要分组的字段 order by 更新时间 desc) rw from 表 a) ...

  5. cas服务器搭建

    一.CAS是Central Authentication Service的缩写,中央认证服务,一种独立开放指令协议.CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的 ...

  6. [置顶] linux c常用函数 (待完善)

    (1)字符测试函数 isalnum(测试字符是否为英文字母或数字) isalpha(测试字符是否为英文字母) isascii(测试字符是否为ASCII码字符) isblank(测试字符是否为空格字符) ...

  7. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #6 使用localmodconfig缩短编译时间

    HACK #6 使用localmodconfig缩短编译时间 本节介绍使用make localmodconfig生成精简的.config文件,缩短内核编译时间的方法.为了能够应对各种各样的环境,发布版 ...

  8. 精《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #4 如何使用Git

    HACK #4 如何使用Git 本节介绍Git的使用方法.Git是Linux内核等众多OSS(Open Source Software,开源软件)开发中所使用的SCM(Source Code Mana ...

  9. 新建网站与新建Asp.Net Web 应用程序的区别

    .net网站和应用程序区别,网站是动态执行的不用编译,他只依赖于自己的文档本身,甚至你用aspx里直接写jsp代码都可以,其实网站可以说只是在.net平台中打开的文档,相当于最初的记事本编码,他并不需 ...

  10. 如何使用C#程序给PDF文件添加编辑域

    PDF文档通常是不能编辑的,但有些时候需要在PDF文档中填写日期或签名之类,就需要在PDF有能编辑的文本域,本文介绍怎样用C#来实现这一功能. 环境 工具:VS2015 语言:C# 操作PDF类库:i ...