基于Windows API的命名管道的封装与使用详解

       命名管道是一种进程间通信(RPC)的方式,类似于socket,命名管道的一端为server,另一端为client,client与server之间支持单向或双向通信。与socket相比,命名管道更适合本地进程间的通信,使用更方便和高效。

       与socket相同,命名管道在通信之前,客户端和服务器端必须建立连接。好比两个人约会,需要事先商量好一个时间在某一个地点(如:某某咖啡厅)见面,见了面后就可以愉快的畅谈了。

        命名管道的名字类似于这个约好的咖啡厅,通过这个名字,客户端与服务端建立连接。

        谁是客户端谁是服务端,建立连接的过程是怎样的? 还是以约会为例,两个人约好了时间在某个咖啡厅见面,肯定有一个人先到有一个人后到,如果先到的人到了咖啡厅看对方没来,认为对方爽约,就立即离开了,则这样的约会一定会失败。所以为了能成功约会,先到的人到了咖啡厅应该等待一段时间,半个小时,1个小时,1天,甚至可以等上10年(忠诚的八公)。这样一般会等到另一个人到来,约会成功,下面就可以愉快的交谈了。先来的人就是服务端,他需要的特殊操作是等待,后来的人是客户端,他来到咖啡厅后,要找到等待他的人,客户端的特殊操作就是连接。

         我封装一个类CPipe,利用Windows提供的API实现了Pipe连接和通信的功能。

         CreatePipe是服务端调用,创建命名管道,为防止重复创建,需要先测试该命名管道是否已经创建(可以使用WaitNamedPipe测试)

BOOL CPipe::CreatePipe(const char* pipename)
{
    if(m_hPipe != INVALID_HANDLE_VALUE)
    {
        CloseHandle(m_hPipe);
        m_hPipe = INVALID_HANDLE_VALUE;
    }
   
    //创建命名管道
    m_hPipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX |
        (OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0), PIPE_TYPE_BYTE |
        PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0,
        60000, NULL);
    
    if(m_hPipe == INVALID_HANDLE_VALUE)
    {
        WT_Error("CPipe::CreatePipe: lasterr=%d\n", GetLastError());
        return FALSE;
    }
    
    CreateThread(0, 0, PipeServerListenProc, this, 0, 0);
    WaitForSingleObject(m_hEvent, 2000);    //wait child thread running

    return TRUE;
}

客户端使用OpenPipe连接命名管道:

BOOL CPipe::OpenPipe(const char* pipename)
{
    if(m_hPipe != INVALID_HANDLE_VALUE)
    {
        CloseHandle(m_hPipe);
        m_hPipe = INVALID_HANDLE_VALUE;
    }
    
    m_hPipe = ::CreateFile(pipename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
        OPEN_EXISTING, OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0, NULL);

    if(m_hPipe == INVALID_HANDLE_VALUE)
    {
        WT_Error("CPipe::CreatePipe: lasterr=%d\n", GetLastError());
        return FALSE;
    }
    
    m_bConnected = TRUE;
    CreateThread(0, 0, PipeClientListenProc, this, 0, 0);
    WaitForSingleObject(m_hEvent, 2000);        //wait child thread running

    return TRUE;
}

如果不想区分服务端和客户端,即:不管是客户端还是服务端用同一个函数完成管道的连接,可使用BindPipe:

BOOL CPipe::BindPipe(DWORD dwPortId)
{
    char pipename[256];
    
    sprintf(pipename, PIPENAME, dwPortId);
    WT_Trace("BindPipe: name=%s\n", pipename);

    if (!WaitNamedPipe(pipename, NMPWAIT_USE_DEFAULT_WAIT))
    {
        //若命名管道不存在则创建(将成为服务端)
        return CreatePipe(dwPortId);
    }
    else
    {
        //若命名管道存在则连接(将成为客户端)
        return OpenPipe(dwPortId);
    }
}

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峻峰飞阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值