2015-07-20 38 views
4

我试图在同一台机器上运行的两个不同程序(在我的情况下,它是一个CentOS7)之间实现IPC。为了只有一种松散耦合,我决定使用IPC的命名管道。因此,我正在玩下面的例子,遇到了不同的问题。IPC:在两个程序之间在C++中使用命名管道

创建并写入管道:

#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的最佳解决方案。此外,我不确定上面描述的行为是否正常,或者我是否以错误的方式使用了命名管道。我也想过套接字,但是我会遇到巨大的阻塞问题。

感谢您的帮助。

+0

看看下面的问题http://stackoverflow.com/q/22714816/540286 –

回答

2

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

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

所以,也许你应该看看System V消息队列(见msggetmsgctlmsgrcvmsgsnd,或POSIX消息队列(见mq_openmq_unlinkmq_sendmq_receive等),它为您提供了可能性,发送和接收“原子”的消息。

3

“首先,如果没有阅读过程中连接到FIFO管道的所有消息,除了写入管道的最后一个迷路”。

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

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

http://beej.us/guide/bgipc/output/html/singlepage/bgipc.html是一个非常好的介绍Unix的ipc,如果你想要更先进的东西,那么在Unix环境下的高级编程理查德史蒂文斯是非常好的。

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

+0

感谢您的答复。如果你将阅读和写作的socked转移到自己的线程中,我不在乎阻塞和非阻塞。对于我来说,套接字的主要问题是如果消息到达,从线程到父节点获得“异步”回调的概念方式。所以我从管道开始 – FredFloete

相关问题