在分析linux系统调用fork,linux系统调用execve时,已经知道:
1.fork时,子进程会复制父进程的打开文件描述符表
2.exec时,进程的打开文件描述符表保持不变

用以下代码观察fork,exec打开文件的变化情况:
父进程fork子进程,睡眠一定时间(方便命令行查看打开文件);
子进程fork孙进程,睡眠一定时间;
孙进程exec新程序,新程序也睡眠一定时间

/* openfiles.c */
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <errno.h>
5
6 #define BUFSIZE 50
7 #define error() \
8 do {    \
9         char buf[BUFSIZE];      \
10         snprintf(buf, BUFSIZE, "[%s][%d][%d]\n", __FILE__, __LINE__, errno);    \
11         perror(buf);    \
12 } while(0);
13
14 int main(int argc, char *argv[])
15 {
16         int pid, fd;
17         int nsecs;
18         char snsecs[20] = {0};
19         int err;
20         if (argc != 2) {
21                 printf("command format: %s sleeptime\n", argv[0]);
22                 return -1;
23         }
24
25         nsecs = atoi(argv[1]);
26         if (nsecs < 0 || nsecs > 120) {
27                 nsecs = 120;
28         }
29         sprintf(snsecs, "%d", nsecs);
30
31         fd = open(argv[0], O_RDONLY);
32         pid = fork();
22                 return -1;
23         }
24
25         nsecs = atoi(argv[1]);
26         if (nsecs < 0 || nsecs > 120) {
27                 nsecs = 120;
28         }
29         sprintf(snsecs, "%d", nsecs);
30
31         fd = open(argv[0], O_RDONLY);
32         pid = fork();
33         if (pid == 0) {
34                 pid = fork();
35                 if(pid == 0) {
36                         err = execl("./exec_openfiles", "exec_openfiles", snsecs, (char *) 0);
37                         if (err) {
38                                 error();
39                                 return -1;
40                         }
41                 } else if (pid < 0) {
42                         error();
43                         return -1;
44                 }
45         } else if (pid < 0) {
46                 error();
47                 return -1;
48         }
49
50         sleep(nsecs);
51         close(fd);
52         return 0;
53 }
/* exec_openfiles.c */
1 #include <stdio.h>
2 #include <fcntl.h>
3
4 int main(int argc, char* argv[])
5 {
6         int fd;
7         int nsecs;
8
9         if (argc != 2) {
10                 printf("command format: %s sleeptime \n", argv[0]);
11                 return -1;
12         }
13
14         nsecs = atoi(argv[1]);
15         if (nsecs <= 0 || nsecs > 120) {
16                 nsecs = 120;
17         }
18
19         fd = open(argv[0], O_RDONLY);
20         sleep(nsecs);
21         close(fd);
22         return 0;
23 }               
/* Makefile */
1 all:
2         gcc openfiles.c -o openfiles
3         gcc exec_openfiles.c -o exec_openfiles

用以下命令观察三个进程打开文件的变化情况:
查看当前终端并运行openfiles:

[redhat@localhost fork_exec_openfiles]$ tty
/dev/pts/6
[redhat@localhost fork_exec_openfiles]$ ./openfiles 90

通过终端查看刚才运行的进程:

[redhat@localhost fork_exec_openfiles]$ ps -t pts/6 -f
UID        PID  PPID  C STIME TTY          TIME CMD
redhat    8165 13780  0 13:20 pts/6    00:00:00 ./openfiles 90
redhat    8166  8165  0 13:20 pts/6    00:00:00 ./openfiles 90
redhat    8167  8166  0 13:20 pts/6    00:00:00 exec_openfiles 90
redhat   13780  2851  0 Jun29 pts/6    00:00:00 bash

通过lsof命令观察以上进程打开的文件:

[redhat@localhost fork_exec_openfiles]$ lsof -p 8165
COMMAND    PID   USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
openfiles 8165 redhat  cwd    DIR  253,0     4096 1068237 /home/redhat/code/syscall/fork_exec_openfiles
openfiles 8165 redhat  rtd    DIR  253,0     4096       2 /
openfiles 8165 redhat  txt    REG  253,0     6245 1068231 /home/redhat/code/syscall/fork_exec_openfiles/openfiles
openfiles 8165 redhat  mem    REG  253,0   141536  134697 /lib/ld-2.12.so
openfiles 8165 redhat  mem    REG  253,0  1880776  134698 /lib/libc-2.12.so
openfiles 8165 redhat    0u   CHR  136,6      0t0       9 /dev/pts/6
openfiles 8165 redhat    1u   CHR  136,6      0t0       9 /dev/pts/6
openfiles 8165 redhat    2u   CHR  136,6      0t0       9 /dev/pts/6
openfiles 8165 redhat    3r   REG  253,0     6245 1068231 /home/redhat/code/syscall/fork_exec_openfiles/openfiles
[redhat@localhost fork_exec_openfiles]$ lsof -p 8166
COMMAND    PID   USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
openfiles 8166 redhat  cwd    DIR  253,0     4096 1068237 /home/redhat/code/syscall/fork_exec_openfiles
openfiles 8166 redhat  rtd    DIR  253,0     4096       2 /
openfiles 8166 redhat  txt    REG  253,0     6245 1068231 /home/redhat/code/syscall/fork_exec_openfiles/openfiles
openfiles 8166 redhat  mem    REG  253,0   141536  134697 /lib/ld-2.12.so
openfiles 8166 redhat  mem    REG  253,0  1880776  134698 /lib/libc-2.12.so
openfiles 8166 redhat    0u   CHR  136,6      0t0       9 /dev/pts/6
openfiles 8166 redhat    1u   CHR  136,6      0t0       9 /dev/pts/6
openfiles 8166 redhat    2u   CHR  136,6      0t0       9 /dev/pts/6
openfiles 8166 redhat    3r   REG  253,0     6245 1068231 /home/redhat/code/syscall/fork_exec_openfiles/openfiles
openfiles 8166 redhat    4r   REG  253,0     6245 1068231 /home/redhat/code/syscall/fork_exec_openfiles/openfiles
[redhat@localhost fork_exec_openfiles]$ lsof -p 8167
COMMAND    PID   USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
exec_open 8167 redhat  cwd    DIR  253,0     4096 1068237 /home/redhat/code/syscall/fork_exec_openfiles
exec_open 8167 redhat  rtd    DIR  253,0     4096       2 /
exec_open 8167 redhat  txt    REG  253,0     5184 1068238 /home/redhat/code/syscall/fork_exec_openfiles/exec_openfiles
exec_open 8167 redhat  mem    REG  253,0   141536  134697 /lib/ld-2.12.so
exec_open 8167 redhat  mem    REG  253,0  1880776  134698 /lib/libc-2.12.so
exec_open 8167 redhat    0u   CHR  136,6      0t0       9 /dev/pts/6
exec_open 8167 redhat    1u   CHR  136,6      0t0       9 /dev/pts/6
exec_open 8167 redhat    2u   CHR  136,6      0t0       9 /dev/pts/6
exec_open 8167 redhat    3r   REG  253,0     6245 1068231 /home/redhat/code/syscall/fork_exec_openfiles/openfiles
exec_open 8167 redhat    4r   REG  253,0     5184 1068238 /home/redhat/code/syscall/fork_exec_openfiles/exec_openfiles

注:
cwd:当前目录
rtd:根目录
txt:程序代码段(可看出exec后的代码段不同)
mem:映射到进程地址空间的动态库
0u,1u,2u:标准输入(对应当前的虚拟终端),标准输出,标准错误
3r,4r:打开的文件

内核导出到proc文件系统中的进程打开文件信息:

[redhat@localhost fork_exec_openfiles]$ ll /proc/8165/fd
总用量 0
lrwx------. 1 redhat redhat 64  6月 30 13:45 0 -> /dev/pts/6
lrwx------. 1 redhat redhat 64  6月 30 13:45 1 -> /dev/pts/6
lrwx------. 1 redhat redhat 64  6月 30 13:45 2 -> /dev/pts/6
lr-x------. 1 redhat redhat 64  6月 30 13:45 3 -> /home/redhat/code/syscall/fork_exec_openfiles/openfiles
[redhat@localhost fork_exec_openfiles]$ ll /proc/8166/fd
总用量 0
lrwx------. 1 redhat redhat 64  6月 30 13:45 0 -> /dev/pts/6
lrwx------. 1 redhat redhat 64  6月 30 13:45 1 -> /dev/pts/6
lrwx------. 1 redhat redhat 64  6月 30 13:45 2 -> /dev/pts/6
lr-x------. 1 redhat redhat 64  6月 30 13:45 3 -> /home/redhat/code/syscall/fork_exec_openfiles/openfiles
lr-x------. 1 redhat redhat 64  6月 30 13:45 4 -> /home/redhat/code/syscall/fork_exec_openfiles/openfiles
[redhat@localhost fork_exec_openfiles]$ ll /proc/8167/fd
总用量 0
lrwx------. 1 redhat redhat 64  6月 30 13:45 0 -> /dev/pts/6
lrwx------. 1 redhat redhat 64  6月 30 13:45 1 -> /dev/pts/6
lrwx------. 1 redhat redhat 64  6月 30 13:45 2 -> /dev/pts/6
lr-x------. 1 redhat redhat 64  6月 30 13:45 3 -> /home/redhat/code/syscall/fork_exec_openfiles/openfiles
lr-x------. 1 redhat redhat 64  6月 30 13:45 4 -> /home/redhat/code/syscall/fork_exec_openfiles/exec_openfiles

父进程:8165
fork的子进程:8166
exec的孙进程:8167

由以上数据可以看出:
1.对比父进程与子进程打开的文件,可知fork后子进程会保持父进程打开的文件不变;父子进程打开的文件在fork之后会相互独立,如上例的子进程新打开的文件4不会出现在父进程打开文件表中。
2.对比子进程与孙进程打开的文件,可知exec后孙进程会保持子进程打开的文件不变(注意子进程文件4是在exec之后打开的);子孙进程打开的文件在exec之后相互独立,如上例的子进程打开的文件4不会出现在孙进程中,孙进程打开的文件4不会出现在子进程中。

所以可以通过打开的文件描述符实现父子进程的通信。
如以下命令

[redhat@localhost fork_exec_openfiles]$ ps -o pid,ppid,comm | cat
PID  PPID COMMAND
8771 13780 ps
8772 13780 cat
13780  2851 bash

就用到了管道和打开文件描述符表来实现通信:

1.shell创建一个管道,并fork两个进程,8771和8772
2.将进程8771的标准输出dup2到管道的写端(如有必要dup2会自动关闭标准输出),然后exec装入ps镜像,ps开始执行,输出写到管道中
3.将进程8772的标准输入dup2到管道的读端(如有必要dup2会自动关闭标准输入),然后exec装入cat镜像,cat开始执行,从管道中读数据
由于fork与exec过程中,打开文件描述符表都不变,所以可以通过以上步骤来实现进程间管道通信。

fork exec时打开文件的变化相关推荐

  1. Unity中打开文件窗口(OpenFileDialog)的几种方法对比

    1 概述 本文链接:http://blog.csdn.net/ithot/article/details/76997237 用Unity以来,一直都没怎么关注过打开对话框去选取本地文件,最近需要用到这 ...

  2. Java打开文件夹/文件

    Java执行本地命令,可以用Runtime实现,也可以用ProcessBuilder实现.无论使用哪种方式,必须要给正确的执行命令,例如打开文件夹的命令是explorer.exe,打开txt文件not ...

  3. 【解决】Word 在试图打开文件时遇到错误 请尝试下列方法:* xxx * xxx * xxx

    [解决]Word 在试图打开文件时遇到错误 请尝试下列方法:* xxx * xxx * xxx 参考文章: (1)[解决]Word 在试图打开文件时遇到错误 请尝试下列方法:* xxx * xxx * ...

  4. c语言打开文件出现分段故障,我不明白为什么我使用ifstream时出现分段错误

    我对C++相当陌生.我试图打开一个文件并将其传递给另一个方法,以便我可以从ifstream读取数据.这是打开文件的方法.我不明白为什么我使用ifstream时出现分段错误 int main() { / ...

  5. python使用open打开文件时显示文件不存在-Python打开文件open()的注意事项

    刚刚用open(fileName)来打开txt格式的文件,总是出现错误,总是找不到文件读取的内容,后来才发现是open()在使用过程中自动关闭了.这里介绍另种方法解决这个问题. 第一种方法. with ...

  6. php怎么关联默认打开程序,win10系统打开文件时提示“请在默认程序控制面板中创建关联”如何解决...

    近日有win10系统用户反映说在打开文件的时候,突然遇到了"请在默认程序控制面板中创建关联"的提示,导致无法打开文件,这该怎么办呢,本教程就给大家带来win10系统打开文件时提示& ...

  7. java 对第三方的异常_Java第三方API调用打开文件方法时抛出异常

    想用Java写一个音乐播放器,使用了Javazoom里的第三方API,调用打开文件的方法open(File file)时,抛出了IOException:Resetting to invalid mar ...

  8. 打开excel文件并写入_双击Excel表格文件时只打开程序不能直接打开文件

    故障描述:双击EXCEL表格文件时仅打开了excel窗口,对应文件不能直接打开文件 ,需通过文件--打开--选中文件来打开. 打开excel后不显示文件内容 注意事项:遇到此类问题时首先通过" ...

  9. python打开方式错误_浅谈python 调用open()打开文件时路径出错的原因

    昨晚搞鼓了一下python的open()打开文件 代码如下 def main(): infile =open("C:\Users\Spirit\Desktop\bc.txt",'r ...

最新文章

  1. 大数据如何有序地“变废为宝”
  2. 几种典型的软件自动化测试框架
  3. Golang的指针类型
  4. 2021年下半年网络规划设计师下午真题及答案解析
  5. ASP.NET MVC中的ActionResult--总结
  6. 滴滴试行“选择路线”功能 乘客可自主选择行驶路线
  7. boolean类型_10、typescript的高级类型
  8. 【转】Windows XP打印共享四大问题及解决方法
  9. FreeBSD 下玩 FC 游戏
  10. oracle自增序列带字母,[原创]Oracle自增序列
  11. 数据分析学习总结笔记01:情感分析
  12. HDLBITS笔记15:组合逻辑之7420芯片
  13. 计算机网络的时间,计算机网络时间同步技术原理介绍
  14. Windows实现快捷键熄屏功能
  15. Android BootLoader及两种刷机模式fastboot和recovery
  16. 【通信协议】单总线协议详解——以DHT11为例
  17. 编程15年40岁程序员的我终于在压力下被迫转行了
  18. [SSD核心技术:FTL 16] 固态硬盘预读技术详解
  19. 【图像融合学习笔记001】图像融合论文及代码网址整理总结(1)——多聚焦图像融合
  20. python基础之Requests库

热门文章

  1. python爬虫-urllib使用
  2. java网络封包_java网络编程(套接字)
  3. 3dmax导出glb格式_3dmax模型透明贴图的制作方法及注意要点
  4. 你了解现在的招聘网站吗?
  5. mac m1笔记本docker 安装nginx
  6. 讨厌广告的人们啊!想点办法
  7. [机器学习]车牌分割
  8. 插入Unicode控制字符-RLO
  9. Notification和NotificationManager的使用(一)
  10. Spark工作原理及基础概念