[英]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消息隊列(請參閱msgget
, msgctl
, msgrcv
, msgsnd
或POSIX消息隊列(請參閱mq_open
, mq_unlink
, mq_send
, mq_receive
等),這樣您就可以發送和接收“原子”消息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.