windows命名管道使用方法

原文地址:https://www.cnblogs.com/lsh123/p/7435401.html

命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。

  将命名管道作为一种网络编程方案时,它实际上建立了一个C/S通信体系,并在其中可靠的传输数据。命名管道服务器和客户机的区别在于:服务器是唯一一个有权创建命名管道的进程,也只有它能接受管道客户机的连接请求。而客户机只能同一个现成的命名管道服务器建立连接。命名管道提供了两种基本通信模式,字节模式和消息模式。在字节模式中,数据以一个连续的字节流的形式在客户机和服务器之间流动。而在消息模式中,客户机和服务器则通过一系列不连续的数据单位进行数据的收发,每次在管道上发出一条消息后,它必须作为一条完整的消息读入。

 

0x01 Server端

 

  代码流程:

  1、创建命名管道:CreateNamedPipe

  2、等待客户端连接:ConnectNamedPipe

  3、读取客户端请求数据:ReadFile

  4、向客户端回复数据:WriteFile

  5、关闭连接:DisconnectNamedPipe

  6、关闭管道:CloseHandle

 

       使用函数:

  CreateNamedPipe创建一个命名的管道

1

2

3

4

5

6

7

8

9

10

HANDLE CreateNamedPipe( 

  LPCTSTR lpName,                  // 管道名称,形式必须为\\.\pipe\pipeName 

  DWORD dwOpenMode,             // 打开管道的模式 

  DWORD dwPipeMode,             // 管道的模式,传输数据的形式 

  DWORD nMaxInstances,               // 最大连接客户端的个数 

  DWORD nOutBufferSize,           // 输出缓冲区的大小 

  DWORD nInBufferSize,               // 输入缓冲区的大小 

  DWORD nDefaultTimeOut,              // 默认的超时时间 

  LPSECURITY_ATTRIBUTES lpSecurityAttributes // 安全属性,一般为NULL 

); 

  ConnectNamedPipe等待一个客户端的连接

1

2

3

4

BOOL ConnectNamedPipe(   

  HANDLE hNamedPipe,         // 命名管道对象 

  LPOVERLAPPED lpOverlapped   // OVERLAPPED结构 

); 

  通信的操作跟我们的文件操作是一样的,通过ReadFile和WriteFile来进行读和写。

 

  通信完之后,调用DisconnectNamedPipe来进行断开连接

1

2

3

BOOL DisconnectNamedPipe(   

  HANDLE hNamedPipe   // 命名管道对象 

); 

  

  Server端源码:

// NamedPipeServer.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"  
#include <windows.h>  
#include <strsafe.h>  

#define BUFSIZE 4096  

DWORD WINAPI InstanceThread(LPVOID);
VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD);

int _tmain(VOID)
{
    BOOL fConnected;
    DWORD dwThreadId;
    HANDLE hPipe, hThread;
    LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\LiudadaNemaedPipe");

    // The main loop creates an instance of the named pipe and   
    // then waits for a client to connect to it. When the client   
    // connects, a thread is created to handle communications   
    // with that client, and the loop is repeated.   

    for (;;)
    {
        hPipe = CreateNamedPipe(
            lpszPipename,             // pipe name            指向管道名称的指针
            PIPE_ACCESS_DUPLEX,       // read/write access    管道打开模式
            PIPE_TYPE_MESSAGE |       // message type pipe    管道模式
            PIPE_READMODE_MESSAGE |   // message-read mode   
            PIPE_WAIT,                // blocking mode   
            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)
        {
            printf("CreatePipe failed");
            return 0;
        }

        // Wait for the client to connect; if it succeeds,   
        // the function returns a nonzero value. If the function  
        // returns zero, GetLastError returns ERROR_PIPE_CONNECTED.   

        fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

        if (fConnected)
        {
            // Create a thread for this client.   
            hThread = CreateThread(
                NULL,              // no security attribute   
                0,                 // default stack size   
                InstanceThread,    // thread proc  
                (LPVOID)hPipe,    // thread parameter   
                0,                 // not suspended   
                &dwThreadId);      // returns thread ID   

            if (hThread == NULL)
            {
                printf("CreateThread failed");
                return 0;
            }
            else CloseHandle(hThread);
        }
        else
        {
            // The client could not connect, so close the pipe.   
            CloseHandle(hPipe);
        }
    }
    return 1;
}

DWORD WINAPI InstanceThread(LPVOID lpvParam)
{
    TCHAR chRequest[BUFSIZE];
    TCHAR chReply[BUFSIZE];
    DWORD cbBytesRead, cbReplyBytes, cbWritten;
    BOOL fSuccess;
    HANDLE hPipe;

    // The thread's parameter is a handle to a pipe instance.   

    hPipe = (HANDLE)lpvParam;

    while (1)
    {
        // Read client requests from the pipe.   
        fSuccess = ReadFile(
            hPipe,        // handle to pipe   
            chRequest,    // buffer to receive data   
            BUFSIZE * sizeof(TCHAR), // size of buffer   
            &cbBytesRead, // number of bytes read   
            NULL);        // not overlapped I/O   

        if (!fSuccess || cbBytesRead == 0)
            break;
        printf((const char*)chRequest);

        GetAnswerToRequest(chRequest, chReply, &cbReplyBytes);

        // Write the reply to the pipe.   
        fSuccess = WriteFile(
            hPipe,        // handle to pipe   
            chReply,      // buffer to write from   
            cbReplyBytes, // number of bytes to write   
            &cbWritten,   // number of bytes written   
            NULL);        // not overlapped I/O   

        if (!fSuccess || cbReplyBytes != cbWritten) break;
    }

    // Flush the pipe to allow the client to read the pipe's contents   
    // before disconnecting. Then disconnect the pipe, and close the   
    // handle to this pipe instance.   

    FlushFileBuffers(hPipe);
    DisconnectNamedPipe(hPipe);
    CloseHandle(hPipe);

    return 1;
}

VOID GetAnswerToRequest(LPTSTR chRequest,
    LPTSTR chReply, LPDWORD pchBytes)
{
    _tprintf(TEXT("%s\n"), chRequest);
    StringCchCopy(chReply, BUFSIZE, TEXT("Message from server"));
    *pchBytes = (lstrlen(chReply) + 1) * sizeof(TCHAR);
}

 

0x01 Client端

 

  代码流程:

  1、打开命名管道:CreateFile

  2、等待服务端响应:WaitNamedPipe

  3、切换管道为读模式:SetNamedPipeHandleState

  4、向服务端发数据:WriteFile

  5、读服务端返回的数据:ReadFile

  6、关闭管道:CloseHandle

 

  WaitNamedPipe来检查一下,命名管道是否存在:

1

2

3

4

BOOL WaitNamedPipe(   

  LPCTSTR lpNamedPipeName,  // 管道名称,形式必须为<span style="font-family: Arial, Helvetica, sans-serif;">\\.\pipe\pipeName</span> 

  DWORD nTimeOut            // 超时时间,给NULL为默认的超时时间 

); 

  SetNamedPipeHandleState 设置管道的一些参数,传输模式

1

2

3

4

5

6

BOOL WINAPI SetNamedPipeHandleState(

  _In_      HANDLE hNamedPipe,//命名管道句柄

  _In_opt_  LPDWORD lpMode,//传输模式,字节流或者信息流

  _In_opt_  LPDWORD lpMaxCollectionCount,//最大字节数

  _In_opt_  LPDWORD lpCollectDataTimeout//超时

);

  

Client端源码:

// NamedPipeClient.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"  
#include <windows.h>  
#include <conio.h>  
#define BUFSIZE 512  

int main(int argc, TCHAR *argv[])
{
    HANDLE hPipe;
    LPTSTR lpvMessage = TEXT("Message from client");
    TCHAR chBuf[BUFSIZE];
    BOOL fSuccess;
    DWORD cbRead, cbWritten, dwMode;
    LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\LiudadaNemaedPipe");

    if (argc > 1)
        lpvMessage = argv[1];

    // Try to open a named pipe; wait for it, if necessary.   

    while (1)
    {
        hPipe = CreateFile(
            lpszPipename,   // pipe name   
            GENERIC_READ |  // read and write access   
            GENERIC_WRITE,
            0,              // no sharing   
            NULL,           // default security attributes  
            OPEN_EXISTING,  // opens existing pipe   
            0,              // default attributes   
            NULL);          // no template file   

                            // Break if the pipe handle is valid.   

        if (hPipe != INVALID_HANDLE_VALUE)
            break;

        // Exit if an error other than ERROR_PIPE_BUSY occurs.   

        if (GetLastError() != ERROR_PIPE_BUSY)
        {
            printf("Could not open pipe");
            return 0;
        }

        // All pipe instances are busy, so wait for 20 seconds.   

        if (!WaitNamedPipe(lpszPipename, 20000))
        {
            printf("Could not open pipe");
            return 0;
        }
    }

    // The pipe connected; change to message-read mode.   

    dwMode = PIPE_READMODE_MESSAGE;
    fSuccess = SetNamedPipeHandleState(
        hPipe,    // pipe handle   
        &dwMode,  // new pipe mode   
        NULL,     // don't set maximum bytes   
        NULL);    // don't set maximum time   
    if (!fSuccess)
    {
        printf("SetNamedPipeHandleState failed");
        return 0;
    }  

       // Send a message to the pipe server.   

    fSuccess = WriteFile(
        hPipe,                  // pipe handle   
        lpvMessage,             // message   
        (lstrlen(lpvMessage) + 1) * sizeof(TCHAR), // message length   
        &cbWritten,             // bytes written   
        NULL);                  // not overlapped   
    if (!fSuccess)
    {
        printf("WriteFile failed");
        return 0;
    }

    do
    {
        // Read from the pipe.   
                 
        fSuccess = ReadFile(
            hPipe,    // pipe handle   
            chBuf,    // buffer to receive reply   
            BUFSIZE * sizeof(TCHAR),  // size of buffer   
            &cbRead,  // number of bytes read   
            NULL);    // not overlapped   

        if (!fSuccess && GetLastError() != ERROR_MORE_DATA)
            break;

        _tprintf(TEXT("%s\n"), chBuf);
        //printf("%S\n", chBuf);
    } while (!fSuccess);  // repeat loop if ERROR_MORE_DATA   

    getch();

    CloseHandle(hPipe);

    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值