通过管道做进程间通信

从通信方式上讲,管道分为单工通信、半双工通信和双工通信,一些操作系统支持管道的双工通信,实质是底层利用两条半双工管道来实现的。另外,普通的管道只能在父子进程间共享做进程间通信,为了实现两个不相干的进程间的通信,可使用命名管道。

父子进程管道通信

使用 pipe() 函数创建管道,fd[0] 用于读,fd[1] 用于写。

#include <unistd.h>
int pipe(int fd[2]);

截取书中示例,子进程做服务端,父进程做客户端,父进程从标准输入接受用户输入的文件名,父进程通过 pipe1[1] 将文件名写入管道,子进程通过 pipe1[0] 读到文件名并打开对应的文件,然后把文件内容通过 pipe2[1] 写到管道,最后父进程通过 pipe2[0] 读到文件内容。

int
main(int argc, char **argv)
{
	int		pipe1[2], pipe2[2];
	pid_t	childpid;

	Pipe(pipe1);	/* create two pipes */
	Pipe(pipe2);

	if ( (childpid = Fork()) == 0) {		/* child */
		Close(pipe1[1]);
		Close(pipe2[0]);

		server(pipe1[0], pipe2[1]);
		exit(0);
	}
		/* 4parent */
	Close(pipe1[0]);
	Close(pipe2[1]);

	client(pipe2[0], pipe1[1]);

	Waitpid(childpid, NULL, 0);		/* wait for child to terminate */
	exit(0);
}

若系统支持管道全双工通信,那么只用一个管道也可以实现该功能。

与 shell 命令的管道通信

使用 popen() 函数可以与 shell 命令进行通信,即程序可以通过管道读取 shell 的输出,或者程序写到管道作为 shell 命令的输入。

命名管道

毫无关联的进程可以使用命名管道进行通信,但命名管道是半双工的,只能以只读或者只写的模式打开命名管道做通信。

同样的功能,书中使用命名管道实现如下所示,为了简便使用了父子进程模式,实际上两个无关联的进程也可以通过命名管道进行通信。

#include	"unpipc.h"

#define	FIFO1	"/tmp/fifo.1"
#define	FIFO2	"/tmp/fifo.2"

void	client(int, int), server(int, int);

int
main(int argc, char **argv)
{
	int		readfd, writefd;
	pid_t	childpid;

		/* 4create two FIFOs; OK if they already exist */
	if ((mkfifo(FIFO1, FILE_MODE) < 0) && (errno != EEXIST))
		err_sys("can't create %s", FIFO1);
	if ((mkfifo(FIFO2, FILE_MODE) < 0) && (errno != EEXIST)) {
		unlink(FIFO1);
		err_sys("can't create %s", FIFO2);
	}

	if ( (childpid = Fork()) == 0) {		/* child */
		readfd = Open(FIFO1, O_RDONLY, 0);
		writefd = Open(FIFO2, O_WRONLY, 0);

		server(readfd, writefd);
		exit(0);
	}
		/* 4parent */
	writefd = Open(FIFO1, O_WRONLY, 0);
	readfd = Open(FIFO2, O_RDONLY, 0);

	client(readfd, writefd);

	Waitpid(childpid, NULL, 0);		/* wait for child to terminate */

	Close(readfd);
	Close(writefd);

	Unlink(FIFO1);
	Unlink(FIFO2);
	exit(0);
}

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

You are commenting using your WordPress.com account. Log Out /  更改 )

Google photo

You are commenting using your Google account. Log Out /  更改 )

Twitter picture

You are commenting using your Twitter account. Log Out /  更改 )

Facebook photo

You are commenting using your Facebook account. Log Out /  更改 )

Connecting to %s

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理