【问题标题】:IPC: Using of named pipes in c++ between two programsIPC:在两个程序之间使用 C++ 中的命名管道
【发布时间】:2015-10-09 09:08:58
【问题描述】:

我试图在同一台机器上运行的两个不同程序之间实现 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 的最佳解决方案。另外我不确定上面描述的行为是否正常,或者我是否以错误的方式使用命名管道。我也考虑过套接字,但是我会遇到巨大的阻塞问题。

感谢您的帮助。

【问题讨论】:

  • 解耦 + 异步消息 + 持久性 = 消息传递。尝试消息传递解决方案 - 请参阅 RabbitMQ,它包含在当前的 CentOS 发行版中。

标签: c++ c linux ipc named-pipes


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 感谢您的回复。如果您将 socked 的读取和写入转移到自己的线程,我不关心阻塞与非阻塞。对我来说,套接字的主要问题是如果消息到达,从线程到父线程的“异步”回调的概念方法。因此我从管道开始
  • @i7clock 完成。
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 2019-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    相关资源
    最近更新 更多