在一些需要传递少量数据的进程通信业务中,采用命名管道通信是一种不错的选择,但是管道通信本身是不跨平台的。如果我们想在不同的平台下使用管道通信就会很麻烦。这里我简单的总结了一下命名管道在windows平台和Linux平台下的使用方法,希望对各位有所帮助。实现的比较简陋,大家可以根据自己的具体业务进行优化封装。
Windows平台管道通信调用
1.服务端创建管道
命名管道通信的服务端需要开辟一个线程,在线程里服务端创建命名管道,然后连接命名管道。通过管道服务端可以接收客户端发送过来的消息,也可以向客户端发送对应的消息。
#include <Windows.h>
bool StartServerPipeWorking()
{
while (true)
{
char buffer[1024];
memset(buffer, 0x00, 1024);
DWORD ReadNum;
//创建命名管道
HANDLE pipe_handle = CreateNamedPipe(L"\\\\.\\Pipe\\Ceshi",
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1,
1024,
1024,
1000,
NULL);
if (pipe_handle == INVALID_HANDLE_VALUE)
{
continue;
}
//连接创建的命名管道
if (ConnectNamedPipe(pipe_handle, NULL))
{
//等待读取管道中的内容
if (ReadFile(pipe_handle, buffer, 1024, &ReadNum, NULL) == FALSE)
{
//读失败之后关闭对应的管道
DisconnectNamedPipe(pipe_handle);
CloseHandle(pipe_handle);
continue;
}
//读取成功之后关闭对应的管道
std::string input_string = std::string(buffer);
std::cout << input_string;
DisconnectNamedPipe(pipe_handle);
CloseHandle(pipe_handle);
}
else
{
CloseHandle(pipe_handle);
}
}
}
2.客户端连接管道进行通信
客户端在使用命名管道的时候,先检查一下对应的命名管道是否存在,如果不存在的话直接发送消息失败,如果存在的话会直接创建对应的管道文件,然后向管道中写入需要发送的数据。
#include <Windows.h>
bool SendPipeMsg(std::string input_str)
{
char buffer[1024];
memset(buffer, 0x00, 1024);
DWORD WriteNum;
if (WaitNamedPipe(L"\\\\.\\Pipe\\Ceshi", 30000) == FALSE)
{
return false;
}
HANDLE hPipe = CreateFile(L"\\\\.\\Pipe\\Ceshi", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hPipe == INVALID_HANDLE_VALUE)
{
return false;
}
if (WriteFile(hPipe, input_str.c_str(), input_str.length(), &WriteNum, NULL) == FALSE)
{
CloseHandle(hPipe);
hPipe = INVALID_HANDLE_VALUE;
return false;
}
CloseHandle(hPipe);
return true;
}
Linux平台管道通信调用
linux平台下的命名管道通信其实和Windows平台下的原理相同,就是在本地创建一个管道文件,然后通过读写管道文件实现进程间的通信。
1.服务端监听
服务端负责创建管道文件,然后监听管道文件中的消息变化,通过读取管道文件中的消息内容实现进程间通信。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int receive_msg()
{
int fd,ret;
//创建管道文件
std::string fifo_path = "/home/test/test_fifo";
ret = mkfifo(fifo_path.toStdString().c_str(), S_IFIFO|0666);
if(ret == -1)
{
return -1;
}
//打开对应的管道文件
fd = open(fifo_path.toStdString().c_str(), O_RDONLY);
if(fd < 0)
{
return -2;
}
char recv[100] = {0};
//读数据,命名管道没数据时会阻塞,有数据时就取出来
read(fd, recv, sizeof(recv));
std::string received_argument = std::string(recv);
close(fd);
}
2.客户端发送
客户端通过向管道文件中写入对应的内容实现和服务端的通信。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int client_send_msg(string msg)
{
int handle;
std::string fifo_path = "/home/test/test_fifo";
handle = open(fifo_path.c_str(), O_WRONLY);
if(handle < 0)
{
return 2;
}
write(handle, msg, msg.length());
close(handle);
}