nohup、&、setsid、fork和fg、bg究竟有啥区别?
目录
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究竟有啥区别?的更多相关文章
- [Linux内核]ctrl-z/fg/bg/nohup/setsid/()与&/disown/screen
转自:https://my.oschina.net/alphajay/blog/65058 My Tips: Ctrl -z -> suspend fg -> ...
- Linux 将进程放入后台执行,解决网络,ssh断开导致进程结束(nohup, setsid, &, disown)
Linux 将进程放入后台执行,解决网络,ssh断开导致进程结束(nohup, setsid, &, disown) 1.nohup 命令 我们知道,当用户注销(logout)或者网络断开 ...
- linux fg&bg
[linux fg&bg] Linux 提供了 fg 和 bg 命令,让我们调度正在运行的任务. 假设你发现前台运行的一个程序需要很长的时间,但是需要干其他的事情,你就可以用 Ctrl-Z , ...
- linux进程后台运行的几种方法 - nohup/setsid/&
linux进程后台运行的几种方法 - nohup/setsid/& [转载] 我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务 ...
- "=="和 equals 方法究竟有什么区别?
"=="和 equals 方法究竟有什么区别? ==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同, 要比较两个基本类型的数据或两个引 ...
- [百家号]雷电3和USB Type-C究竟有什么区别?
雷电3和USB Type-C究竟有什么区别? https://baijiahao.baidu.com/s?id=1617271490773519582&wfr=spider&for=p ...
- linux 后台运行进程 fg bg ctrl+z nohup
fg.bg.jobs.&.nohup.ctrl+z.ctrl+c 命令 一.& 加在一个命令的最后,可以把这个命令放到后台执行,如 watch -n 10 sh test.sh &am ...
- nohup命令与&区别,jobs,fg,bg,Ctrl-Z、Ctrl-C、Ctrl-D
&方式: Unix/Linux下一般想让某个程序在后台运行,很多都是使用 & 在程序结尾来让程序自动运行.比如我们要运行mysql在后台: /usr/local/my ...
- Linux运行与控制后台进程的方法:nohup, setsid, &, disown, screen
我们经常会碰到这样的问题,用ssh登录了远程的Linux服务器,运行了一些耗时较长的任务,结果却由于网络等的不稳定导致任务中途失败.这是由于在用户注销(logout)或者网络断开时,终端会收到 HUP ...
随机推荐
- hadoop之 hadoop日志存放路径
环境:[root@hadp-master hadoop-2.7.4]# hadoop versionHadoop 2.7.4 Hadoop的日志大致可以分为两类: (1).Hadoop系统服务输出的日 ...
- php 文件上传$_FILES中error返回值详解
用PHP上传文件时,我们会用程序去监听浏览器发送过来的文件信息,首先会通 过$_FILES[fieldName]['error']的不同数值来判断此欲上传的文件状态是否正常.$_FILES[field ...
- VS2017开发Linux平台上的程序
重装系统后安装VS2015时卡住了,于是试试看VS2017怎样,听说还支持调Linux.发现VS2017跟12/13/15又有了新的飞跃,竟然支持模块化下载,对于我这种主要写C++简直是个福音,勾了L ...
- scrollWidth,clientWidth,offsetWidth的区别 ---转载的
转载自博客:http://www.cnblogs.com/kongxianghai/p/4192032.html 通过一个demo测试这三个属性的差别. 说明: scrollWidth:对象的实际内容 ...
- 把MacBook里的电影导入到iPad
主要是用iTunes -> 文件 -> 添加到资料库,然后选择影片 -> 同步 -> 应用.在iPad上点开视频APP即可. 怎样才能把mac里的电影放到ipad里_百度知道 ...
- 图片采集器_PHP
现在国内模仿“pinterest”的越来越多了,之前我做过一个基于chrome浏览器上的一个“图片采集工具”,类似于“花瓣网“那样的,初期我觉得挺简单,后来做起来发现还是挺复杂的,特别是整合到你自己的 ...
- ZOJ-3230-Solving the Problems
/*ZOJ Problem Set - 3230Solving the Problems ------------------------------------------------------- ...
- 有了 itchat, python 调用微信个人号从未如此简单(新增 py3 支持)
itchat 是一个开源的微信个人号接口. 近期完成了 py3 与文档的完善,欢迎各位使用与测试. 使用不到三十行的代码,你就可以完成一个能够处理所有信息的微信机器人. 当然,该 api 的使用远不止 ...
- 20165233 实验二 Java面向对象程序设计
20165233 实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验步 ...
- 【CentOS 6.5】【转】新版本linux生成xorg.conf
新版本的linux如何生成xorg.conf 较新版本的linux系统都已经没有xorg.conf文件,但是有时候为了对显示做微调或为了支持多屏显示等原因,还需要手工生成一个xorg.conf,然后根 ...