首先说明linux进程之间通信的主要方式。大型程序大多会涉及到某种形式的进程间通信,一个较大型的应用程序设计成可以相互通信的“碎片”,从而就把一个任务分到多个进程中去。进程间通信的方法有三种方式:
1, 管道(pipe)
2,System v IPC 机制 ,包括消息队列,信号量,共享内存
3,套接字(socket)
管道机制在UNIX开发的早期就已经提供了,它在本机上的两个进程间的数据传递表现的相当出色;套接字是在BSD(Berkeley Software Development)中出现的,现在的应用也相当的广泛;而System V IPC机制Unix System V 版本中出现的。
首先讲管道机制,会在以后把其他的通信机制都讲到。
管道分为pipe(无名管道)和FIFO(命名管道),它们都是通过内核缓冲区按先进先出的方式数据传输,管道一端顺序地写入数据,另一端顺序地读入数据读写的位置都是自动增加,数据只读一次,之后就被释放。1 ,PIPE无名管道
调用格式为int pipe(int filedes[2]);,文件描述符filedes[0]用来读数据,filedes[1]用来写数据。如果要求程序的可移植性好,就按照习惯的用法来编程。调用成功时,返回值为0;错误时,返回-1,并设置错误代码errno:
管道在用户程序看起来就像一个打开的文件,通过
read(filedes[0],void *_buf,size_t _nypes);
或者write
(filedes[1],void *_buf,size_t _nypes)
向这个文件读写数据其实是在读写内核缓冲区。下面给出实例:
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
int pipedes[2];//pipe输入输出文件描述符
char s[13]="hello world!";
int pid;
if(pipe(pipedes)==-1)//创建管道失败
{
perror("pipe error!");
exit(EXIT_FAILURE);
}
if(pid=fork()<0)//创建子进程失败
{
perror("fork is error!\n");
return -1;
}
else if(pid==0)//在子进程中
{
printf("now,write data to pipe\n");
if(write(pipedes[1],s,13)==-1)
{
perror("write error!");
exit(EXIT_FAILURE);
}
else
{
printf("the written data is :%s\n",s);
exit(EXIT_SUCCESS);
}
}
else if(pid > 0)//在父进程中
{
sleep(4);//保证子进程写操作完成
printf("now read data from pipe!\n");
if(read(pipedes[0],s,13)==-1)
{
perror("read error!");
exit(EXIT_FAILURE);
}
printf("the data is %s\n",s);
}
return 0;
}
达到预期效果。
2,有名管道
无名管道时临时的,在完成通信后就自动消失,且只能在具有亲元关系的进程间实现通信。有名管道他是一个存在的特殊文件,可以在不同的进程间进行通信。用户可以使用shell来创建有名管道,也可以使用mkfifo函数来创建有名管道,可以使用read和write进行读写操作。
下面直接给出操作实例:
fifo_read.c
/** 管道通信:有名管道
* 无名管道只能用于具有亲缘关系的进程之间,而有名管道可以在互不相关的两个进程间
* 实现彼此通信。要注意,FIFO严格按照先进先出的规则,对管道及FIFO的读总是从开始
* 处返回数据,对它们的写则把数据添加到末尾,不支持lseek等文件定位操作。
*
* 有名管道的创建使用mkfifo()。创建成功后就可以使用open、read、write这些函数了。
* 读管道部分
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/*在这里设置打开管道文件的mode为只读形式*/
#define FIFOMODE (O_CREAT | O_RDWR | O_NONBLOCK)
#define OPENMODE (O_RDONLY | O_NONBLOCK)
#define FIFO_SERVER "myfifo"
int main(void)
{
char buf[100];
int fd;
int readnum;
/*创建有名管道,设置为可读写,无阻塞,如果不存在则按照指定权限创建*/
if ((mkfifo(FIFO_SERVER, FIFOMODE) < 0) && (errno != EEXIST)) {
printf("cannot create fifoserver\n");
exit(1);
}
printf("Preparing for reading bytes... ...\n");
/*打开有名管道,并设置非阻塞标志*/
if ((fd = open(FIFO_SERVER, OPENMODE)) < 0) {
perror("open");
exit(1);
}
while (1) {
/*初始化缓冲区*/
bzero(buf, sizeof(buf));
/*读取管道数据*/
if ((readnum = read(fd, buf, sizeof(buf))) < 0) {
if (errno == EAGAIN) {
printf("no data yet\n");
}
}
/*如果读到数据则打印出来,如果没有数据,则忽略*/
if (readnum != 0) {
buf[readnum] = '\0';
printf("read %s from FIFO_SERVER\n", buf);
}
sleep(1);
}
return 0;
}
fifo_write.c
#include <stdio.h>#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
/*特别注意写管道时,设置打开管道文件的格式必须为可写*/
#define FIFO_SERVER "myfifo"
#define OPENMODE (O_WRONLY | O_NONBLOCK)
int main(int argc, char **argv)
{
int fd;
int nwrite;
/*打开管道文件,可写非阻塞*/
if ((fd = open(FIFO_SERVER, OPENMODE)) < 0) {
perror("open");
exit(1);
}
/*如果没有在命令行中写入参数,那么要重新运行程序*/
if (argc == 1) {
printf("Please send something\n");
exit(1);
}
/*向管道文件中写入数据,在这里要用strlen,如果用sizeof,则只是4个字节的指针长度*/
if ((nwrite = write(fd, argv[1], strlen(argv[1]))) < 0) {
if (errno == EAGAIN) {
printf("The FIFO has not been read yet.Please try later\n");
}
}
else {
printf("write %s to FIFO\n", argv[1]);
}
return 0;
}