linux IPC 通信 study 一:管道
2015-11-03 17:41
393 查看
linux 进程通信机制:分为基于system V 和posix。
常用的通信方式分为:
(1) 管道pipe和命名管道fifo.
(2) 信号signal
(3) 信号量semphore
(4) 消息队列 msg queue
(5) 共享内存share memory
(6) 套接字socket
详解如下:
1.1. 匿名管道通信pipe,它把一个进程的输入和另外一个进程的输出连接起来,读进程从头部读出数据,写进程从尾部写入数据,每个管道都是单向的,当需要双向通信时就需要建立起两个管道。管道两端的进程均将该管道看做一个文件,传输遵循“先入先出”(FIFO)的规则。数据从一个管道中读出后,便会从管道中删除,其他读进程再也不会读到该数据,当管道为空时,读进程会被阻塞,当管道满时,写进程也会被阻塞掉。管道实际上就是个只存在于内存中的文件,对这个文件的操作要通过两个已经打开文件进行,它们分别代表管道的两端。管道是一种特殊的文件,它不属于某一种文件系统,而是一种独立的文件系统,有其自己的数据结构。
默认情况下,匿名管道pipe是半双工通信(posix允许实现支持全双工管道)。
pipe只能在具有公共祖先的两个进程之间使用。
当要读管道时,在进程中要就爱那个写管道关闭,同理要写管道时,在进程中也要将读管道关闭。常量PIPE_BUF规定了内核的管道缓冲区大小。
sample code:
[cpp]
view plaincopy
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
int main(int argc, char **argv)
{
int ret = 0;
int pipe_fd[2] = {0};
char buf[128] = {0};
char *p_write_buf;
int num = 0;
pid_t child_id;
if (pipe(pipe_fd) < 0 ) {
fprintf(stderr, "create pipe failed\n");
return -1;
}
child_id = fork();
if (child_id < 0){
fprintf(stderr, "fork error\n");
return -1;
} else if(0 == child_id) { /*child process*/
fprintf(stdout,"child process...\n");
close(pipe_fd[1]);
sleep(2);/*wait for father write pipe*/
num = read(pipe_fd[0], buf, 128);
if (num > 0)
fprintf(stdout, "child read:%s\n", buf);
close(pipe_fd[0]);
exit(0);
} else {/*father process*/
fprintf(stdout, "father process..\n");
close(pipe_fd[0]);
ret = write(pipe_fd[1], "haha,", 5);
//ret = write(pipe_fd[1], "write first", 20);
fprintf(stdout, "father write1 ret = %d\n", ret);
ret = write(pipe_fd[1], "pipe!", 5);
//ret = write(pipe_fd[1], "write second", 20);
fprintf(stdout, "father write2 ret = %d\n", ret);
close(pipe_fd[1]);
sleep(3);
waitpid(child_id, NULL, 0);
exit(0);
}
return ret;
}
1.2 命名管道FIFO:不同于匿名管道,FIFO有一个pathname与之相关联,以文件的形式存在于文件系统中,无论是否是父子进程,都可以通过访问FIFO。
sample code:
写fifo
测试程序中有2 个问题:
(1)FIFO中的数据被读出来一次之后,程序不退出,再次读取就读不到任何内容了,写程序一直再写。
(2)FIFO中的内容被读走之后,FIFO buffer中的数据反而没有被清空,程序退出,再执行,还是能够读出同样的内容?
(3)当有多个写进程时,写进程必须全部启动起来,然后再启动读进程,工作正常,但是一旦读进程跑起来的之后,再启动加入的写进程写入的内容反而不能被读出来。如果只有一个读一个写,读写任意一个先启动都不会影响。
常用的通信方式分为:
(1) 管道pipe和命名管道fifo.
(2) 信号signal
(3) 信号量semphore
(4) 消息队列 msg queue
(5) 共享内存share memory
(6) 套接字socket
详解如下:
1.1. 匿名管道通信pipe,它把一个进程的输入和另外一个进程的输出连接起来,读进程从头部读出数据,写进程从尾部写入数据,每个管道都是单向的,当需要双向通信时就需要建立起两个管道。管道两端的进程均将该管道看做一个文件,传输遵循“先入先出”(FIFO)的规则。数据从一个管道中读出后,便会从管道中删除,其他读进程再也不会读到该数据,当管道为空时,读进程会被阻塞,当管道满时,写进程也会被阻塞掉。管道实际上就是个只存在于内存中的文件,对这个文件的操作要通过两个已经打开文件进行,它们分别代表管道的两端。管道是一种特殊的文件,它不属于某一种文件系统,而是一种独立的文件系统,有其自己的数据结构。
默认情况下,匿名管道pipe是半双工通信(posix允许实现支持全双工管道)。
pipe只能在具有公共祖先的两个进程之间使用。
当要读管道时,在进程中要就爱那个写管道关闭,同理要写管道时,在进程中也要将读管道关闭。常量PIPE_BUF规定了内核的管道缓冲区大小。
sample code:
[cpp]
view plaincopy
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
int main(int argc, char **argv)
{
int ret = 0;
int pipe_fd[2] = {0};
char buf[128] = {0};
char *p_write_buf;
int num = 0;
pid_t child_id;
if (pipe(pipe_fd) < 0 ) {
fprintf(stderr, "create pipe failed\n");
return -1;
}
child_id = fork();
if (child_id < 0){
fprintf(stderr, "fork error\n");
return -1;
} else if(0 == child_id) { /*child process*/
fprintf(stdout,"child process...\n");
close(pipe_fd[1]);
sleep(2);/*wait for father write pipe*/
num = read(pipe_fd[0], buf, 128);
if (num > 0)
fprintf(stdout, "child read:%s\n", buf);
close(pipe_fd[0]);
exit(0);
} else {/*father process*/
fprintf(stdout, "father process..\n");
close(pipe_fd[0]);
ret = write(pipe_fd[1], "haha,", 5);
//ret = write(pipe_fd[1], "write first", 20);
fprintf(stdout, "father write1 ret = %d\n", ret);
ret = write(pipe_fd[1], "pipe!", 5);
//ret = write(pipe_fd[1], "write second", 20);
fprintf(stdout, "father write2 ret = %d\n", ret);
close(pipe_fd[1]);
sleep(3);
waitpid(child_id, NULL, 0);
exit(0);
}
return ret;
}
1.2 命名管道FIFO:不同于匿名管道,FIFO有一个pathname与之相关联,以文件的形式存在于文件系统中,无论是否是父子进程,都可以通过访问FIFO。
sample code:
#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define FIFO "./myfifo" int main(int argc,char** argv) { int ret = 0; char buf[128] = {0}; int fd; int nbytes_read; int idx = 0; if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)) fprintf(stdout, "cannot create fifo \n"); /*read as a file */ fd = open(FIFO,O_RDONLY|O_NONBLOCK,0); if (fd == -1) { fprintf(stdout, "open failed"); exit(1); } while(1) { memset(buf,0,sizeof(buf)); nbytes_read = read(fd, buf, 128); fprintf(stdout, "FIFO read %d times, len: %d ", idx++, nbytes_read); if(nbytes_read == -1) { if(errno==EAGAIN) fprintf(stdout, "fifo empty\n"); } fprintf(stdout, "context: %s \n", buf); sleep(1); } pause(); unlink(FIFO); close(fd); return ret; }
写fifo
#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define FIFO "./myfifo" main(int argc,char** argv) { int ret = 0; int fd = 0; char buf[128] = {0}; int nbytes_write = 0; fd = open(FIFO, O_WRONLY|O_NONBLOCK, 0); while (1) { fprintf(stdout, "pls input:\n"); fgets(buf,128, stdin); nbytes_write = write(fd, buf, strlen(buf)); printf("file write num = %d\n", nbytes_write); if(nbytes_write == -1) { if(errno==EAGAIN) fprintf(stdout, "The FIFO has not been read yet.\n"); } else { fprintf(stdout, "FIFO write: %s\n",buf); } } close(fd); return ret; }
测试程序中有2 个问题:
(1)FIFO中的数据被读出来一次之后,程序不退出,再次读取就读不到任何内容了,写程序一直再写。
(2)FIFO中的内容被读走之后,FIFO buffer中的数据反而没有被清空,程序退出,再执行,还是能够读出同样的内容?
(3)当有多个写进程时,写进程必须全部启动起来,然后再启动读进程,工作正常,但是一旦读进程跑起来的之后,再启动加入的写进程写入的内容反而不能被读出来。如果只有一个读一个写,读写任意一个先启动都不会影响。
相关文章推荐
- linux下rarlinux安装后找不到rar命令处理方法
- centos编译安装svn
- linux网卡统计信息清零
- centos 新增用户, 然后他在主目录添加网站403Forbbiden
- Linux C中读取/dev/input/event设备来判断键盘按键是否按下
- linux线程异常保护
- linux一天一命令博客链接
- linux下静态库的ranlib使用
- linux ar命令用法
- linux的crontab定时服务备份mysql数据
- Centos7 安装python3的独立环境
- Linux下使用Eclipse开发Hadoop应用程序
- Linux下crontab定时执行脚本
- java代码调用linux命令,生成.pem公钥私钥证书
- centos7 挂载virtualbox 中无法挂载共享文件
- PostgreSQL在CentOS下的源码安装
- 理解LInux路由
- 如何找出Linux系统中内置模块的信息
- centos7安装配置lnmp
- linux chmod 使用方法