命名管道通信
概述
该代码演示了使用命名管道进行进程间通信的方法。命名管道是一种在无关的进程之间创建双向通信通道的 IPC(进程间通信)机制。在这个例子中,我们创建了一个服务器和一个客户端,它们可以通过命名管道交换数据。
文件
comm.hpp
:包含用于创建和移除命名管道的实用函数的头文件。
client.cpp
:客户端应用程序,将用户输入写入命名管道。
server.cpp
:服务器应用程序,从命名管道读取数据并显示。
使用方法
-
编译:使用 C++ 编译器编译代码。例如,使用 g++:
1 2
| g++ client.cpp -o client g++ server.cpp -o server
|
-
运行:
-
在一个终端中启动服务器:
-
在另一个终端中启动客户端:
-
通信:客户端提示用户输入,输入的数据会被写入命名管道,服务器会读取并显示接收到的数据。
-
结束:要退出程序,使用适当的退出命令(例如,Ctrl+C
)。
工作原理
命名管道创建和移除
- 使用
createFifo
函数创建命名管道。在这之前,通过 umask(0)
确保文件权限不受限制。
- 使用
removeFifo
函数移除命名管道。这两个函数确保了正确的权限和错误处理。
客户端写入
- 客户端通过
open
函数以只写方式打开命名管道。
- 使用
write
将用户输入写入管道。
服务器读取
- 服务器通过
open
函数以只读方式打开命名管道。
- 使用
read
从管道中读取数据,并在控制台上显示。
附加说明
- 代码中的异常处理确保了在发生错误时程序能够优雅地退出并输出错误信息。
- 这个例子是一个基本的命名管道通信演示,可以根据需要扩展和修改以满足更复杂的通信需求。
comm.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #pragma once
#include <iostream> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string> #include <cstring> #include <cerrno> #include <stdexcept> #include <cassert>
#define NAMED_PIPE "./myPipe"
bool createFifo(const std::string &path) { umask(0);
if (mkfifo(path.c_str(), 0600) == 0) return true; else throw std::runtime_error("无法创建命名管道: " + std::string(strerror(errno))); }
void removeFifo(const std::string &path) { if (unlink(path.c_str()) != 0) throw std::runtime_error("无法删除命名管道: " + std::string(strerror(errno))); }
|
client.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include "comm.hpp"
int main() { std::cout << "客户端启动!\n";
int wfd = open(NAMED_PIPE, O_WRONLY);
if (wfd < 0) exit(1);
while (true) { char buffer[1024]; memset(buffer, 0, sizeof(buffer));
std::cout << "请输入: "; fgets(buffer, sizeof(buffer), stdin);
if (strlen(buffer) > 0) buffer[strlen(buffer) - 1] = 0;
ssize_t writeBytes = write(wfd, buffer, strlen(buffer));
assert(writeBytes == strlen(buffer)); (void)writeBytes; }
close(wfd); }
|
server.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include "comm.hpp"
int main() { bool res = createFifo(NAMED_PIPE); assert(res); (void)res;
std::cout << "服务器启动!等待客户端启动中...\n";
int rfd = open(NAMED_PIPE, O_RDONLY); std::cout << "客户端已启动,可以开始通信!\n";
if (rfd < 0) exit(1);
while (true) { char buffer[1024]; memset(buffer, 0, sizeof(buffer));
ssize_t readBytes = read(rfd, buffer, sizeof(buffer) - 1);
if (readBytes > 0) { std::cout << "客户端 -> 服务器: " << buffer << "\n"; } else if (readBytes == 0) { std::cout << "客户端退出,服务器也退出!\n"; break; } else { std::cout << "错误: errno " << errno << " | 错误信息: " << strerror(errno) << std::endl; break; } }
close(rfd);
removeFifo(NAMED_PIPE); }
|
makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| .PHONY: all
all: client server
client: client.cpp g++ -o $@ $^ -std=c++11
server: server.cpp g++ -o $@ $^ -std=c++11
.PHONY: clean
clean: rm -f server client
|