Linux中的dup和dup2函数

 分类: Server

在前面一篇“用Python给Linux编写守护进程”的文章中,讲到了如何利用python给linux编写一个守护函数。文章讲到了守护进程不依赖用户终端,所以输出的信息用户是察觉不到的,但是有时候我们又需要记录一些信息。例如web服务中,我们可以需要记录访问日志,错误日志等等;在著名的web服务器nginx中,我们可以通过access_log和error_log分别指定访问日志和错误日志的存放位置。

首先要讲到linux系统的标准输入(stdin)标准输出(stdout)和标准错误(stderr): 在Unix和类Unix系统中,如同某些编程语言接口一样,标准流是当一个电脑程序运行时,在它和它的环境间(典型为终端),事先连接的输入和输出频道。这三个I/O链接称作“标准输入”、“标准输出”和“标准错误输出”。(1)标准输入,标准输出和标准错误的文件描述符分别为0,1,2。在正常进程中,这三个标准流通常都是指向用户使用的终端号。即进程通过终端获取输入,也通过终端输入正常信息和错误信息。

下面是三个文件描述符的指向信息:

[root@home fd]# ls -la
total 0
dr-x------ 2 root root  0 Aug  3 14:52 .
dr-xr-xr-x 7 root root  0 Aug  3 14:52 ..
lrwx------ 1 root root 64 Aug  3 14:52 0 -> /dev/pts/0
lrwx------ 1 root root 64 Aug  3 14:52 1 -> /dev/pts/0
lrwx------ 1 root root 64 Aug  3 14:52 2 -> /dev/pts/0

从上述描述中,我们可以知道,只要我们把相应的文件描述符重新绑定给记录文件而不是终端,那么进程输出的信息就自然被记录到文件当中了。Linux中有两个比较常用的函数dup和dup2用来复制文件描述符,用法如下:
int dup(int filedes)
int dup2(int oldfd,int newfd)

先介绍dup,当dup函数执行时,它会把原来的文件状态复制并返回新的文件描述符,而且这个文件描述符将会是系统中最小的文件描述符。利用dup函数的这个特点,可以做到重定向系统的标准输入输出:

#!/usr/bin/env python
import os,sys
error_log="/var/error.log"
access_log="/var/access.log"	

ehandle=open(error_log,"a")
ahandle=open(access_log,"a")

os.close(sys.stdout.fileno())
os.close(sys.stderr.fileno())

fdout=os.dup(ahandle.fileno())
fderr=os.dup(ehandle.fileno())
ehandle.close()
ahandle.close()

if fdout==1:
        print "Stdin Redirection success!"
else:
        print "error stdin redirection"


if fderr==2:
        print "Stderr Redirection success!"
else:
        print "error stderr redirection"

监控结果,发现进程问的标准输出和标准错误都已经被重定向,print函数的输出的内容已经出现在了access_log当中。

在来说一下dup2函数,从上面的dup函数,我们了解到,系统会自动指定一个没有使用的最小文件描述符给进程。而dup2函数可以让用户自己指定文件描述符,它的作用是复制文件描述符,将newfd描述符所对应的文件表 改成 oldfd所对应的文件表项。之后,newfd与oldfd指向同一个文件表。这样就将newfd重定向到oldfd:

#!/usr/bin/env python
import os,sys
error_log="/var/error.log"
access_log="/var/access.log"

ehandle=open(error_log,"a")
ahandle=open(access_log,"a")

os.dup2(ehandle.fileno(),sys.stderr.fileno())
os.dup2(ahandle.fileno(),sys.stdout.fileno())

ehandle.close()
ahandle.close()

上述两个函数均可实现linux下标准流的重定向,dup函数理解起来更加简单,dup2操作起来更加简单。理解和掌握这两个函数,对于理解linux系统编程是非常有帮助的。

发表回复