Linux进程间通信——命名管道应用实例
发布日期:2021-06-29 12:42:20 浏览次数:2 分类:技术文章

本文共 5554 字,大约阅读时间需要 18 分钟。

    命名管道克服了管道没有名字的限制,同时除了具有管道的功能外(也是半双工),它还允许无亲缘关系进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。

下面程序fifo_write.c周期的往管道中写入数据:

/*=============================================================================  #     FileName: fifo_write.c#         Desc: write data to name pipe#       Author: Licaibiao  #      Version:   #   LastChange: 2017-01-10   #      History:  =============================================================================*/ #include 
#include
#include
#include
#include
#include
#include
#include
int main(){ const char *fifo_name = "/tmp/my_fifo"; int pipe_fd = -1; int data_fd = -1; int res = 0; static int i = 0; const int open_mode = O_WRONLY; char buffer[PIPE_BUF + 1]; char test_data[PIPE_BUF]; if(access(fifo_name, F_OK) == -1) { printf ("Create the fifo pipe.\n"); res = mkfifo(fifo_name, 0777); if(res != 0) { fprintf(stderr, "Could not create fifo %s\n", fifo_name); exit(EXIT_FAILURE); } } printf("Process %d opening FIFO O_WRONLY\n", getpid()); pipe_fd = open(fifo_name, open_mode); printf("Process %d result %d\n", getpid(), pipe_fd); if(pipe_fd !=-1) { while(1) { sprintf(test_data,"test number %d \n",i++); printf("Process %d write data to name pipe: %s",getpid(),test_data); res = write(pipe_fd, test_data, PIPE_BUF); if(res == -1) { printf("write error on name pipe !\n"); exit(EXIT_FAILURE); } else { sleep(2); } } } else { exit(EXIT_FAILURE); } close(pipe_fd);}

下面程序fifo_read.c周期的从管道中读取数据:

/*=============================================================================  #     FileName: fifo_read.c#         Desc: read data from name pipe#       Author: Licaibiao  #      Version:   #   LastChange: 2017-01-10   #      History:  =============================================================================*/ #include 
#include
#include
#include
#include
#include
#include
#include
int main(){ const char *fifo_name = "/tmp/my_fifo"; int pipe_fd = -1; int res = 0; int open_mode = O_RDONLY; char buffer[PIPE_BUF + 1]; int bytes_read = 0; int bytes_write = 0; memset(buffer, '\0', sizeof(buffer)); printf("Process %d opening FIFO O_RDONLY\n", getpid()); pipe_fd = open(fifo_name, open_mode); printf("Process %d result %d\n",getpid(), pipe_fd); if(pipe_fd != -1) { while(1) { res = read(pipe_fd, buffer, PIPE_BUF); if(res>0) { printf("Process %d read data from name pipe :%s",getpid(),buffer); } sleep(2); } close(pipe_fd); } else { exit(EXIT_FAILURE); } printf("Process %d finished, %d bytes read\n", getpid(), bytes_read); exit(EXIT_SUCCESS);}

编译运行结果为:

root@ubuntu:/home/share/pipe# vim fifo_write.c root@ubuntu:/home/share/pipe# vim fifo_read.c root@ubuntu:/home/share/pipe# gcc fifo_read.c -o fifo_readroot@ubuntu:/home/share/pipe# gcc fifo_write.c -o fifo_writeroot@ubuntu:/home/share/pipe# root@ubuntu:/home/share/pipe# lsfifo_read  fifo_read.c  fifo_write  fifo_write.croot@ubuntu:/home/share/pipe# ./fifo_write &[1] 88963root@ubuntu:/home/share/pipe# Process 88963 opening FIFO O_WRONLYroot@ubuntu:/home/share/pipe# root@ubuntu:/home/share/pipe# ./fifo_read Process 88964 opening FIFO O_RDONLYProcess 88963 result 3Process 88963 write data to name pipe: test number 0 Process 88964 result 3Process 88964 read data from name pipe :test number 0 Process 88963 write data to name pipe: test number 1 Process 88964 read data from name pipe :test number 1 Process 88963 write data to name pipe: test number 2 Process 88964 read data from name pipe :test number 2 Process 88963 write data to name pipe: test number 3 Process 88964 read data from name pipe :test number 3 Process 88963 write data to name pipe: test number 4 Process 88964 read data from name pipe :test number 4 Process 88963 write data to name pipe: test number 5 Process 88964 read data from name pipe :test number 5 ^Croot@ubuntu:/home/share/pipe# Process 88963 write data to name pipe: test number 6 [1]+  Broken pipe             ./fifo_writeroot@ubuntu:/home/share/pipe# ls /tmpat-spi2         my_fifo             pulse-PKdhtXMmr18n  ssh-fbQHGxSG2651      vgauthsvclog.txt.0  vmware-licaibiaokeyring-x9fH8E  pulse-2L9K88eMlGn7  pulse-TIYtyXUn5vZV  unity_support_test.0  VMwareDnD           vmware-rootroot@ubuntu:/home/share/pipe#

     先在后台运行write函数,我们可以看到pipe被阻塞了,直到有一个进程读取pipe它才得意继续运行。最后当没有进程读取管道数据时,写入端写入数据将返回错误。另外,我们可以在tmp目录下看到我们创建的管道 my_fifo:

 这里总结一下name pipe 需要注意的事项:

1、就是程序不能以O_RDWR(读写)模式打开FIFO文件进行读写操作,而其行为也未明确定义,因为如一个管道以读/写方式打开,进程就会读回自己的输出,同时我们通常使用FIFO只是为了单向的数据传递。

2、就是传递给open调用的是FIFO的路径名,而不是正常的文件。(如:const char *fifo_name = "/tmp/my_fifo"; )

3、第二个参数中的选项O_NONBLOCK,选项O_NONBLOCK表示非阻塞,加上这个选项后,表示open调用是非阻塞的,如果没有这个选项,则表示open调用是阻塞的。

4、关于阻塞问题:

  • 对于以只读方式(O_RDONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_RDONLY),除非有一个进程以写方式打开同一个FIFO,否则它不会返回;如果open调用是非阻塞的的(即第二个参数为O_RDONLY | O_NONBLOCK),则即使没有其他进程以写方式打开同一个FIFO文件,open调用将成功并立即返回。
  • 对于以只写方式(O_WRONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_WRONLY),open调用将被阻塞,直到有一个进程以只读方式打开同一个FIFO文件为止;如果open调用是非阻塞的(即第二个参数为O_WRONLY | O_NONBLOCK),open总会立即返回,但如果没有其他进程以只读方式打开同一个FIFO文件,open调用将返回-1,并且FIFO也不会被打开。

5、管道安全问题:

    有一种情况是:一个FIFO文件,有多个进程同时向同一个FIFO文件写数据,而只有一个读FIFO进程在同一个FIFO文件中读取数据时,会发生数据块的相互交错。不同进程向一个FIFO读进程发送数据是很普通的情况。这个问题的解决方法,就是让写操作的原子化。系统规定:在一个以O_WRONLY(即阻塞方式)打开的FIFO中, 如果写入的数据长度小于等待PIPE_BUF,那么或者写入全部字节,或者一个字节都不写入。如果所有的写请求都是发往一个阻塞的FIFO的,并且每个写记请求的数据长度小于等于PIPE_BUF字节,系统就可以确保数据决不会交错在一起。
 

 


2019.06.24更新

命名管道的一些读写规则:

  • 以非阻塞只写方式打开时,在多进程中同时写入数据,注意写入的大小和写入的原子性。
  • 以非阻塞只写方式打开时,如果没有一个进程在读管道,打开会失败。
  • 以非阻塞只写方式打开时,如果所有读管道进程关闭,写进程会收到SIGPIPE信号如果写进程不对SIGPIPE信号进行处理,会导致写进程退出。

 

 

转载地址:https://caibiao-lee.blog.csdn.net/article/details/54320515 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:linux进程间通信——信号集函数
下一篇:程序,进程,线程的概念及进程间通信——学习目录

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月17日 14时48分39秒