函数名: dup2
功 能: 复制文件句柄
用 法: int dup2(int oldhandle, int newhandle);
#include <unistd.h>
define STDIN_FILENO 0 /* Standard input. */ #define STDOUT_FILENO 1 /* Standard output. */ #define STDERR_FILENO 2 /* Standard error output. */
问题描述:
在写一个小型web服务器的过程中,把返回的socket描述符sockfd用dup2函数复制给标准输出描述符,这样才调用cgi程序的时候对于所有原本要输出到标准输出的流全部都会写入到sockfd,返回给客户端。但是有一个问题:就是我想用lsz来传输一个文件,客户端一直没有返回。我查看了下进程,发现一直都卡在lsz里面的。我想了很久,发现 lsz 发送文件的过程中会有输出,这时候打输出就默认输出到sockfd里面了,导致我程序死了。也就是说怎么样实现cgi程序里,在需要和终端交互的时候实现交互?
代码:
/*************server.c*****************/ setenv("QUERY_STRING", cgiargs, 1); Dup2(fd, STDOUT_FILENO); //把标准输出的句柄复制到文件句柄 Execve(filename, emptylist, environ); /* Run CGI program */
Execve里面执行的程序就是lsz,用于向串口传输文件。
问题解决:
在cgi程序里面,主要做法:把不需要传回给sockfd的输出返回给终端就行了,那么就不会写到客户端的sockfd里面了。那么怎么实现呢?可以这样:因为在这个时候sockfd==STDOUT_FILENO,只需要把STDOUT_FILENO先保存下来oldsockfd,然后用open重新打开终端,然后用dup2把返回的描述符和STDOUT_FILENO联系在一起,这个时候输出又重定向到STDOUT_FILENO去了,然后输出结束,再用dup2把oldsockfd又和STDOUT_FILENO联系在一起。这时候输出又重定向到sockfd去了,下面是代码:
int oldsockfd = STDOUT_FILENO; int ttyfd = open("/dev/tty",O_RDWR); dup2(ttyfd,STDOUT_FILENO); //do somethings dup2(STDOUT_FILENO,oldsockfd);