一、简介
命名管道(NamedPipe)是服务器进程和一个或多个客户进程之间通信的单向或双向管道。不同于匿名管道的是:命名管道可以在不相关的进程之间和不同计算机之间使用,服务器建立命名管道时给它指定一个名字,任何进程都可以通过该名字打开管道的另一端,根据给定的权限和服务器进程通信。
二、接口函数介绍
创建命名管道 | |
CreateNamedPipe | 创建命名管道 |
ConnectNamedPipe | 服务器端等待客户端连接命名管道。若调用此函数之前,客户端已经调用CreateFile连接到了此实例,ConnectNamedPipe返回FALSE,并且GetLastError()返回ERROR_PIPE_CONNECTED,这是一个正常的连接,虽然函数返回了FALSE |
WriteFile/ReadFile | |
DisconnectNamedPipe | 断开一个客户与一个命名管道的连接,服务器端强制关闭命名管道的客户端;客户进程仍然需要调用CloseHandle。服务器端可以进一步再与其他客户端连接 |
CloseHandle | 关闭命名管道 |
连接到命名管道某个实例 | |
WaitNamedPipe | 如果指定的命名管道没有实例存在,即没有服务端创建该命名管道,函数无视超时等待时间直接返回0。如果函数执行成功返回TRUE,表示至少有一个命名管道的实例有效 |
CreateFile | 使用CreateFile函数打开命名管道的一个句柄,CreateFile可能会打开管道失败,因为该实例有可能被服务端关闭或被已经被其他客户端打开 |
WriteFile/ReadFile | |
CloseHandle |
ConnectNamedPipe参数简介:
备注:实际应用中,我们用管道传输音视频帧数据,需要配置PipeMode为PIPE_TYPE_MESSAGE、PIPE_READMODE_MESSAGE。
三、示例
客户端代码示例:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string>
/*client demo code*/
int main( ) {
HANDLE PipeHandle;
DWORD BytesWritten;
const char* message = "hello world";
std::string name = "\\\\.\\pipe\\test";
TCHAR pipename[MAX_PATH] = { 0 };
#ifdef UNICODE
_stprintf_s(pipename, MAX_PATH, _T("%S"), name.c_str());//%S宽字符
#else
_stprintf_s(pipename, MAX_PATH, _T("%s"), name.c_str());//%s单字符
#endif
if (WaitNamedPipe(pipename, NMPWAIT_WAIT_FOREVER) == 0)
{
printf("WaitNamedPipe failed with error %d\n",
GetLastError());
return -1;
}
// Open the named pipe file handle
if ((PipeHandle = CreateFile(pipename,
GENERIC_READ | GENERIC_WRITE, 0,
(LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE)NULL)) == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed with error %d\n", GetLastError());
return -1;
}
if (WriteFile(PipeHandle, message, strlen(message), &BytesWritten, NULL) == 0)
{
printf("WriteFile failed with error %d\n", GetLastError());
CloseHandle(PipeHandle);
return -1;
}
printf("Wrote %d bytes", BytesWritten);
CloseHandle(PipeHandle);
return 0;
}
服务端代码示例:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string>
/*server demo code*/
int main(void)
{
HANDLE PipeHandle;
DWORD BytesRead;
CHAR buffer[256];
std::string name = "\\\\.\\pipe\\test";
TCHAR pipename[MAX_PATH] = { 0 };
#ifdef UNICODE
_stprintf_s(pipename, MAX_PATH, _T("%S"), name.c_str());//%S宽字符
#else
_stprintf_s(pipename, MAX_PATH, _T("%s"), name.c_str());//%s单字符
#endif
if ((PipeHandle = CreateNamedPipe(pipename,
PIPE_ACCESS_DUPLEX, //open mode
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // pipe mode
1,//Num. of MaxInstances: between 1 and PIPE_UNLIMITED_INSTANCES
0, // out buffer size
0, // in buffer size
1000, //timeout
NULL //Security descriptor
)) == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe failed with error %d\n",
GetLastError());
return 0;
}
printf("Server is now running\n");
if (ConnectNamedPipe(PipeHandle, NULL) == 0)
{
printf("ConnectNamedPipe failed with error %d\n", GetLastError());
CloseHandle(PipeHandle);
return 0;
}
if (ReadFile(PipeHandle, buffer, sizeof(buffer), &BytesRead, NULL) <= 0)
{
printf("ReadFile failed with error %d\n", GetLastError());
CloseHandle(PipeHandle);
return 0;
}
printf("%.*s\n", BytesRead, buffer);
if (DisconnectNamedPipe(PipeHandle) == 0)
{
printf("DisconnectNamedPipe failed with error %d\n",
GetLastError());
return 0;
}
CloseHandle(PipeHandle);
return 0;
}
注意示例中先执行服务端,后执行客户端。
四、管道状态查询两种办法
1)PowerShell
命令行:[System.IO.Directory]::GetFiles("\\.\\pipe\\")
2)Google Chrome浏览器
命令行:file://.//pipe//
五、参考
2、命名管道客户端使用说明
3、函数列表
4、创建命名管道参数详解
5、关于模式PIPE_TYPE_MESSAGE模式