管道本身不需要提供常规文件,但它们可以有一个独特的、全局可见的名称,这个名称由你必须指定的(未使用的)文件名提供。如果有的话,文件的内容由库处理。
在相关进程之间(例如同一进程层次结构中的子进程和父进程)进行通信的(简单)管道,其中管道句柄可以轻松地传递给其他进程。
另一种类型的管道称为“命名管道”,用于任何关系的进程,其中可以使用全局名称查找管道句柄(如我链接的问题的答案中所解释的)。你可以把管道看作是直接连接的说话管道,允许两个进程使用读写函数随意聊天。在Linux上,管道是单向的(一次只能有一个人说话,另一个人听)。在这种情况下,需要两个管道进行双向异步IO(https://unix.stackexchange.com/questions/53641/how-to-make-bidirectional-pipe-between-two-programs)。输入和输出的即时缓冲区被抽象化了。就像网络套接字一样。
我建议编译接受答案中的漂亮示例以进行操作:
https://dev59.com/yHE85IYBdhLWcg3wbS1h#2789967
编辑
带有错误处理的示例代码。将pipe.h和pipe.c视为库(链接NamedPipeReader和NamedPipeWriter)。
此代码需要进一步测试,但该代码能够以任何顺序(重新)打开命名管道。
pipe.h
#ifndef PIPE_H_
#define PIPE_H_
#include <errno.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef __cplusplus
extern "C"
{
#endif
int open_named_pipe(const char* const name, const int permissions, const int mode, int* pipe_created);
#ifdef __cplusplus
}
#endif
#endif
pipe.c
#include "pipe.h"
#include <stdio.h>
int open_named_pipe(const char* const name, const int permissions, const int mode, int* pipe_created)
{
int fd;
assert(name);
assert(permissions);
assert(pipe_created);
if (0 == mkfifo(name, permissions))
{
*pipe_created = 1;
printf("Successfully created named pipe '%s'\n", name);
}
else
{
switch (errno)
{
case EEXIST:
printf("Opened existing named pipe '%s'\n", name);
break;
default:
fprintf(stderr, "Failed to create or access named pipe '%s'\n", name);
perror(" ");
return -1;
};
}
fd = open(name, mode);
if (fd < 0)
{
perror("Could not open pipe for writing");
if (*pipe_created)
{
if (0 == unlink(name))
{
*pipe_created = 0;
}
else
{
perror("Failed to unlink named pipe");
}
}
}
return fd;
}
NamedPipeReader.c
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include "pipe.h"
const char* const pipe_name = "/tmp/myfifo";
const int pipe_permissions = 0600;
const size_t read_buffer_size = 1024;
const size_t read_retry_delay = 25000;
int fd = -1;
int pipe_created = 0;
char* read_buffer = NULL;
void signal_handler(int signal)
{
fprintf(stderr, "cought signal %d\n", signal);
}
void exit_handler(void)
{
if (read_buffer)
free(read_buffer);
if (fd >= 0)
close(fd);
if (pipe_created == 0)
unlink(pipe_name);
}
int main()
{
int run = 1;
int received = 0;
atexit(&exit_handler);
signal(EPIPE, signal_handler);
signal(EACCES, signal_handler);
read_buffer = (char*) malloc(read_buffer_size);
if (!read_buffer)
{
perror("Failed to allocate buffer");
return EXIT_FAILURE;
}
restart: ;
if(fd >= 0)
close(fd);
fd = open_named_pipe(pipe_name, pipe_permissions, O_RDONLY, &pipe_created);
if (fd < 0)
{
return EXIT_FAILURE;
}
while (run)
{
assert(fd >= 0);
assert(read_buffer_size > 1);
received = read(fd, read_buffer, read_buffer_size - 1);
if (received > 0)
{
read_buffer[received] = '0';
printf("local process %llu received: %s\n", (unsigned long long) getpid(), read_buffer);
}
else if (received == 0)
{
usleep(read_retry_delay);
printf("Restarting...\n");
goto restart;
}
else
{
switch (errno)
{
case EAGAIN:
usleep(read_retry_delay);
break;
case EPIPE:
case EBADF:
case EBADFD:
perror("Pipe error");
printf("Restarting...\n");
goto restart;
default:
perror("Pipe error");
return EXIT_FAILURE;
};
}
}
return EXIT_SUCCESS;
}
NamedPipeWriter.c
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include "pipe.h"
const char* const pipe_name = "/tmp/myfifo";
const int pipe_permissions = 0600;
const size_t write_buffer_size = 1024;
const size_t write_retry_delay = 25000;
const size_t write_interval = 1000000;
int fd = -1;
int pipe_created = 0;
char* write_buffer = NULL;
void signal_handler(int signal)
{
fprintf(stderr, "cought signal %d\n", signal);
}
void exit_handler(void)
{
if (write_buffer)
free(write_buffer);
if (fd >= 0)
close(fd);
if (pipe_created == 0)
unlink(pipe_name);
}
int main()
{
int run = 1;
int sent = 0;
int msg_len = 0;
atexit(&exit_handler);
signal(EPIPE, signal_handler);
signal(EACCES, signal_handler);
write_buffer = (char*) malloc(write_buffer_size);
if (!write_buffer)
{
perror("Failed to allocate buffer");
return EXIT_FAILURE;
}
restart: ;
if(fd >= 0)
close(fd);
fd = open_named_pipe(pipe_name, pipe_permissions, O_WRONLY, &pipe_created);
if (fd < 0)
{
return EXIT_FAILURE;
}
while (run)
{
msg_len = snprintf(write_buffer, write_buffer_size, "Greetings from process %llu\n", (unsigned long long) getpid());
{
char* msg_ptr = write_buffer;
char* msg_end = write_buffer + msg_len;
while (msg_ptr != msg_end)
{
assert(fd >= 0);
assert(msg_ptr < msg_end);
sent = write(fd, msg_ptr, msg_end - msg_ptr);
if (sent > 0)
{
msg_ptr += sent;
}
else if (sent == 0)
{
usleep(write_retry_delay);
}
else
{
switch (errno)
{
case EAGAIN:
usleep(write_retry_delay);
break;
case EPIPE:
case EBADF:
case EBADFD:
perror("Pipe error");
printf("Restarting...\n");
goto restart;
default:
perror("Pipe error");
return EXIT_FAILURE;
};
}
}
printf("Written: %s\n", write_buffer);
usleep(write_interval);
}
}
return EXIT_SUCCESS;
}