进程间通信是指两个不同进程间可以交换数据,因此操作系统应提供两个进程可以同时访问的内存空间。
普通管道(PIPE)
为了完成进程间通信,需要创建管道,管道不属于进程的资源,而是和套接字一样属于操作系统。因此两个进程通过操作系统提供的内存空间进行通信。下面是创建管道的函数:
#include<unistd.h>
int pipe(int filedes[2]);
//成功时返回0,失败时返回-1
- filedes[0]---通过管道接收数据时使用的文件描述符,即管道出口
- filedes[1]---通过管道传输数据时使用的文件描述符,即管道入口
父进程与子进程数据交换示例:
#include<stdio.h>
#include<unistd.h>
#define BUF_SIZE 30
int main()
{
int fds[2];
char str[]="Who are you?";
char buf[BUF_SIZE];
pid_t pid;
pipe(fds);//pipe创建管道
pid=fork();
if(pid==0)
{
write(fds[1],str,sizeof(str));//子进程向管道传递字符串
}else{
read(fds[0],buf,BUF_SIZE); //父进程从管道接收字符串
puts(buf);
}
return 0;
}
下面通过一个管道进行双向通信:
#include<stdio.h>
#include<unistd.h>
#define BUF_SIZE 30
int main(int argc,char *argv[])
{
int fds[2];
char str1[]="Who are you?";
char str2[]="Thank you for your message";
char buf[BUF_SIZE];
pid_t pid;
pipe(fds);
pid=fork();
if(pid==0){
write(fds[1],str1,sizeof(str1));
sleep(2);
read(fds[0],buf,BUF_SIZE);
printf("Child proc output:%s \n",buf);
}
else{
read(fds[0],buf,BUF_SIZE);
printf("Parent proc output:%s \n",buf);
write(fds[1],str2,sizeof(str2));
sleep(3);
}
return 0;
}
向管道传递数据时,先读的进程会把数据取走。数据进入管道后成为无主数据,通过read函数先读取数据的进程将得到数据,即使该进程将数据传到了管道。因此子进程中代码sleep(2)是关键,如果没有,子进程将读回自己向管道发送的数据,结果父进程调用read函数后将无限期等待数据进入管道。
因此在进行双向通信时可以创建两个管道,各自负责不同的数据流,如下面示例所示:
#include<stdio.h>
#include<unistd.h>
#define BUF_SIZE 30
int main(int argc,char *argv[])
{
int fds1[2],fds2[2];
char str1[]="Who are you?";
char str2[]="Thank you for your message";
char buf[BUF_SIZE];
pid_t pid;
pipe(fds1),pipe(fds2);
pid=fork();
if(pid==0){
write(fds1[1],str1,sizeof(str1));
read(fds2[0],buf,BUF_SIZE);
printf("Child proc output:%s \n",buf);
}
else{
read(fds1[0],buf,BUF_SIZE);
printf("Parent proc output:%s \n",buf);
write(fds[2],str2,sizeof(str2));
sleep(3);
}
return 0;
}
命名管道(FIFO)
通常的管道只能连接相关的进程,使用命名管道可以连接不相关的进程,并且可以独立于进程存在。称这样的命名管道为FIFO(先进先出队列)。
创建FIFO
#include<sys/types.h>
int mkfifo(char *filoname,mode_t mode);
使用指定的权限模式来创建FIFO。mkfifo命令通常调用这个函数
删除FIFO
#include<sys/types.h>
void unlink(char *filoname);
此函数可以用来删除FIFO
监听FIFO的连接
#include<sys/types.h>
int open(char *filoname,O_RDONLY);
open函数阻塞进程直到某一进程打开FIFO进行写操作
通过FIFO会话
#include<sys/types.h>
int open(char *filename,O_WRONLY)
open函数阻塞进程直到某一进程打开FIFO进行读取操作。
两进程通过FIFO进行通信
发送进程用write调用,而监听进程使用read调用。写进程调用close来通知读进程通信结束。
下面两个shell脚本是基于FIFO的时间/日期服务的服务器和客户端程序:
#!/bin/sh
# time server
while true;do
rm -f /tmp/time_fifo
mkfifo /tmp/time_fifo
date> /tmp/time_fifo
done
#! /bin/sh
# time client
cat /tmp/time_fifo