繁体   English   中英

IPC:在两个程序之间使用c ++中的命名管道

[英]IPC: Using of named pipes in c++ between two programs

我正在尝试在同一台机器上运行的两个不同程序之间实现IPC(在我的例子中是CentOS7)。 为了获得一种松耦合,我决定使用一个命名管道进行IPC。 因此,我正在玩以下示例并遇到了不同的问题。

创建和写入管道:

#include <sys/types.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>

using namespace std;

main()  {
 int fd;
 char * myfifo = new char [12];
 strcpy(myfifo, "./tmp/myfifo1");

 /* create the FIFO (named pipe) */
 mkfifo(myfifo, 0666);
 /* write "Hi" to the FIFO */
 fd = open("./tmp/myfifo1", O_WRONLY ); //open(myfifo, O_WRONLY | O_NONBLOCK);
 if (fd == -1) {
     perror("open");
     return EXIT_FAILURE;
 } 
 printf("File open\n");
 write(fd, "entry [1]", sizeof("entry [1]"));
 sleep(1);
 write(fd, "entry [2]", sizeof("entry [2]"));
 sleep(2);
 write(fd, "entry [3]", sizeof("entry [3]"));
 printf("Content written\n");
 close(fd);
 printf("Connection closed\n");
 /* remove the FIFO */
 unlink(myfifo);
 return 0;
}

读管道:

#include <sys/types.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <string>
#include <iostream>

using namespace std;

main()  {
 int fd; 
 fd_set set_a;

 char * myfifo = new char [12];
 strcpy(myfifo, "./tmp/myfifo1");
 char buffer[1024];

 fd = open("./tmp/myfifo1", O_RDONLY | O_NONBLOCK);
 if (fd == -1) {
     perror("open");
     return EXIT_FAILURE;
 } 
 ssize_t bytes;
 size_t total_bytes = 0;
 printf("\nDropped into read pipe\n");
 while(1){
     if((bytes = read(fd, buffer, sizeof(buffer))) > 0){
         std::string message(&buffer[22]);
         total_bytes += (size_t)bytes;
         printf("%i", bytes);

         printf("Message: %s\n", message.c_str());
         memset(&buffer[0], 0, sizeof(buffer));
     }else{
         if (errno == EWOULDBLOCK) {
             printf("\ndone reading (%d bytes)\n", (int)total_bytes);
             //break;
         }
         printf("No message\n");
         sleep(2);
     } 
 }
 return EXIT_SUCCESS;
}

我觉得命名管道的行为非常不灵活我用我的测试程序想出来的。 首先,如果没有读取进程附加到fifo管道,除了写入管道的最后一个消息之外的所有消息都会丢失(或者一般来说,只有在读取过程附加到管道之后才能读取最后一条消息)。 如果你在管道中写入多条消息,那么读取之前的所有消息(例如轮询)将被解释为一条消息(我知道它们可以被\\ 0分割)。

命名管道的主要目标是a)系统日志和b)用户身份验证的类型。 命名管道的异步完全符合我的需要。 但无论如何,我不确定命名管道是否是不同程序之间IPC的最佳解决方案。 此外,我不确定上面描述的行为是否正常,或者我是否以错误的方式使用命名管道。 我也考虑过套接字,但后来我会遇到很大的阻塞问题。

谢谢你的帮助。

“首先,如果没有读取进程附加到fifo管道,除了写入管道的最后一个消息之外的所有消息都会丢失”。

不,他们没有。 使用cat而不是你的(糟糕的写:D)阅读过程,你将得到所有的消息。

你是对的。 管道是面向字节的,而不是面向消息的。 如果你想要消息,还有其他的IPC(例如,SysV消息队列)。

Beej的Unix指南IPC是Unix ipc的一个很好的介绍,如果你想要更高级的东西,那么Richard Stevens 在Unix环境中的高级编程非常好。

就用户身份验证而言,请查看Unix套接字。

看起来你正在尝试使用管道来实现它们不适合的设计。 首先, 必须为管道的另一侧“附加”读取过程。 如果您尝试打开管道进行写入并且没有读取过程, open将挂起等待它或返回-1并将errno设置为ENXIO (当使用O_NONBLOCK标志时)。 所以命名管道是系统中的一种流行点,其中两个进程相遇以交换数据;)

第二 - 不要将写入管道视为发送消息。 管道是一个“字节流”。 你可以写一次10个字节,阅读器可以进行5次读取,每次2个字节,反之亦然:你可以写5次2个字节,读者可以一次读取它们。 因此,如果您计划通过管道发送某种“消息”,您应该开发某种最小传输协议(例如,使用'\\ 0'字节作为分隔符,如上所述)。

所以,也许您应该查看System V消息队列(请参阅msggetmsgctlmsgrcvmsgsnd或POSIX消息队列(请参阅mq_openmq_unlinkmq_sendmq_receive等),这样您就可以发送和接收“原子”消息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM