进程间通信之命名管道

命名管道简述

命名管道是进程间通信的另一种方式,它屏蔽了底层的网络协议细节,在我们不了解网络协议时,可以依靠命名管道实现网络通信。命名管道作为一个种网络编程方案时,它实际上是建立了一个客户机/服务器通信体系,并在其中可靠的传输数据,传输方式包括双工通信和单工通信。

此外,一个命名管道的所有实例共享同一个管道名,但是每一个实例均拥有独立的缓存和句柄,并且为客户机-服务端提供一个分离的管道,保证多个管道能够在同一时间使用同一个命名管道。

命名管道是围绕Windows文件系统设计的一种机制,采用“命名管道文件系统(Name Pipe File System,NPFS)”接口;因此客户机和服务端可利用标准的Win32文件系统函数(ReadFile和WriteFile)来进行数据收发。

命名管道的提供两种通信模式:字节模式和消息模式

  • 在字节模式下,数据以一个连续的字节流的形式在客户机和服务器之间流动
  • 在消息模式下,客户机和服务器则通过一系列的不连续的数据单位,进行数据的收发,每次在管道上发出一个消息后,它必须作为一个完整的消息读入

命名管道特点

和匿名管道相比,命名管道有以下特点:

  • 支持同一台机器上通信,也可以跨网络间通信
  • 支持双工通信、客户机->服务端、服务端->客户机三种通信方式,双工通信不需要创建两个管道
  • 一个命名管道的所有实例共享同一个管道名
  • 管道是FIFO结构

客户机和服务端区别

  • 服务器是唯一一个有权创建命名管道的进程,也只有它能接受客户机的连接请求
  • 客户机只能同一个现成的命名管道服务器建立连接

管道命名规范

命名管道的名字格式必须是\\ServerName\pipe\PipeName形式,名称pipe是固定的字符串,不能修改;命名管道有以下两种形式:

  • 若在本机通信,则ServerName为 圆点.,代表本地机器
  • 若在不同计算机之通信,ServerName则为远程服务器的名称或者地址
编码流程

服务端流程:

  1. 创建命名管道:CreateNamedPipe

  2. 等待客户端连接:ConnectNamedPipe

  3. 数据读写:ReadFile / WriteFile

  4. 关闭连接:DisconnectNamedPipe

  5. 关闭管道:CloseHandle

代码如下:

#include "stdafx.h"
#include <Windows.h>

const int  BUFSIZE = 1024;
const TCHAR szPipeName[128] = {_T("\\\\.\\pipe\\mypipename")} ;

int _tmain(int argc, _TCHAR* argv[])
{
    int nRet = -1;
    //创建一个命名管道实例
    //若需要同时支持多个客户端连接,需要多次调用CreateNamedPipe
    HANDLE hPipe = CreateNamedPipe( 
        szPipeName,             // pipe name 
        PIPE_ACCESS_DUPLEX |     // read/write access 
        FILE_FLAG_OVERLAPPED,
        PIPE_TYPE_MESSAGE,
        PIPE_UNLIMITED_INSTANCES, // max. instances  
        BUFSIZE,                  // output buffer size 
        BUFSIZE,                  // input buffer size 
        0,                        // client time-out 
        NULL);                    // default security attribute 

    if (hPipe == INVALID_HANDLE_VALUE) 
    {
        _tprintf(TEXT("CreateNamedPipe failed, error code=%d.\n"), GetLastError()); 
        return -1;
    }
    else
    {
        _tprintf(_T("create namepipe success...\n"));
    }

    HANDLE hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
    if (NULL == hEvent)
    {
        CloseHandle(hPipe);
        return -1;
    }
    
    //等待客户端连接请求
    do 
    {
        OVERLAPPED ovlap;
        ZeroMemory(&ovlap, sizeof(ovlap));
        ovlap.hEvent = hEvent;

        if (!ConnectNamedPipe(hPipe,&ovlap))
        {
            //ERROR_IO_PENDING代表正则进行中
            if (ERROR_IO_PENDING != GetLastError())
            {
                _tprintf(_T("等待连接客户端失败...\n"));
                break;
            }
        }

        _tprintf(_T("waiting client connected...\n"));

        if (WAIT_FAILED == WaitForSingleObject(hEvent, INFINITE))
        {
            break;
        }

        nRet = 0;

    } while (0);

    if (nRet != 0)
    {
        CloseHandle(hPipe);
        CloseHandle(hEvent);
        return -1;
    }
    else
    {
       _tprintf(_T("a client has connected server...\n"));
    }

    TCHAR szMsgBuf[BUFSIZE]  = {_T("123456789")};
    DWORD dwWrite = 0;
    //客户端和服务端完成连接
    //向管道写入数据
    if (!WriteFile(hPipe,szMsgBuf,wcslen(szMsgBuf)*2,&dwWrite,NULL))
    {
        _tprintf(_T("write file error...%d\n"),::GetLastError());
    }
    else
    {
       _tprintf(_T("write file success %s...\n"),szMsgBuf);
    }

    //Flush the pipe to allow the client to read the pipe's contents 
    // before disconnecting
    FlushFileBuffers(hPipe);
    DisconnectNamedPipe(hPipe);
    CloseHandle(hPipe);
    CloseHandle(hEvent);
	return 0;
}

客户端流程

  1. 打开命名管道:CreateFile

  2. 等待服务端响应:WaitNamedPipe

  3. 管道数据读写:WriteFile / ReadFile

  4. 关闭管道:CloseHandle

#include "stdafx.h"
#include <Windows.h>

const TCHAR szPipeName[128] = {_T("\\\\.\\pipe\\mypipename")} ;
const int BUF_SIZE = 1024;

int _tmain(int argc, _TCHAR* argv[])
{
    TCHAR szBuf[BUF_SIZE] = {};
    DWORD dwRead = 0;

    //等待服务端有可以利用的命名管道
    if (!WaitNamedPipe(szPipeName,NMPWAIT_WAIT_FOREVER))
    {
        _tprintf(_T("wait namepipe error...\n"));
        return -1;
    }
    
    //打开可以用的命名管道
    HANDLE hPipe = CreateFile(szPipeName,
        GENERIC_READ| GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    if (INVALID_HANDLE_VALUE == hPipe)
    {
        return -1;
    }

    //从管道中读取数据
    if (!ReadFile(hPipe,szBuf,sizeof(szBuf),&dwRead,NULL))
    {
        _tprintf(_T("read file error...\n"));
    }
    else
    {
        _tprintf(_T("read file success %s...\n"),szBuf);
    }

    //关闭句柄
    CloseHandle(hPipe);
    return 0;
}

运行结果:
在这里插入图片描述

更多资料可以参考:

https://docs.microsoft.com/zh-cn/windows/win32/ipc/named-pipes

https://blog.csdn.net/j6915819/article/details/8437274

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值