「命名管道」进程间通信——Console程序设计

来源:互联网 发布:pascal编程语言 下载 编辑:程序博客网 时间:2024/06/03 17:35

命名管道服务端

 

//创建一个异步(重叠I/O)服务端,反射客户端发来的消息

 

#pragma once

 

#include <stdio.h>

#include <tchar.h>

#include <Windows.h>

 

#define NUM_PIPES 5

#define BUFFER_SIZE 256

 

 

int _tmain(int argc, _TCHAR* argv[])

{

    HANDLE PipeHandles[NUM_PIPES];

    DWORD BytesTransferred;

    CHAR Buffer[NUM_PIPES][BUFFER_SIZE];

    INT i;

    OVERLAPPED Ovlap[NUM_PIPES];

    HANDLE Event[NUM_PIPES];

 

    BOOL DataRead[NUM_PIPES];

 

    DWORD Ret;

    DWORD Pipe;

 

    for(i = 0; i < NUM_PIPES; i++)

    {

        // 创建命名管道实例

        // PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED 双工异步模式

        // PIPE_TYPE_BYTE | PIPE_READMODE_BYTE 字节流通信

        // NUM_PIPES 连接实例数

        // 默认缓冲区大小,等待超时时间1秒,默认安全符

        if ((PipeHandles[i] = CreateNamedPipe(TEXT("////.//PIPE//Tc"),

            PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,

            PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, NUM_PIPES,

            0, 0, 1000, NULL)) == INVALID_HANDLE_VALUE)

        {

            printf("创建命名管道实例 %d 失败, 错误代码: %d/n",

                  i, GetLastError());

            return i;

        }

 

        // 创建无名的事件对象

        // 使用默认安全符,手工复位方式,初试状态为无信号,名称无

        if ((Event[i] = CreateEvent(NULL, TRUE, FALSE, NULL))

            == NULL)

        {

            printf("创建命名管道事件对象实例 %d 失败,错误代码: %d/n",

                i, GetLastError());

            continue;

        }

 

        // 管道实例状态初始化

        DataRead[i] = FALSE;

 

        // 初始化用于异步操作的结构

        ZeroMemory(&Ovlap[i], sizeof(OVERLAPPED));

        Ovlap[i].hEvent = Event[i];

 

        // 启动监听

        // 因异步模式,该函数立刻返回,通过索检错误代码,判断是否成功

        if (ConnectNamedPipe(PipeHandles[i], &Ovlap[i]) == 0)

        {

            if (GetLastError() != ERROR_IO_PENDING)

            {

                printf("启动命名管道实例 %d 监听模式失败,错误代码: %d/n",

                      i, GetLastError());

                CloseHandle(PipeHandles[i]);

                return i;

            }

        }

    }

 

    printf("命名管道服务开始运行/n");

 

    while(TRUE)

    {

        // 开始等候一个事件对象发生变化

        // NUM_PIPES 事件对象最大数

        // Event 事件对象句柄数组指针

        // FALSE 当其中一个信号量有效时就向下执行,为TRUE 则等待所有信号量有效再往下执行

        // INFINITE 等待时间为无限

        if ((Ret = WaitForMultipleObjects(NUM_PIPES, Event,

            FALSE, INFINITE)) == WAIT_FAILED)

        {

            printf("等待信号时发生错误,错误代码: %d/n",

                GetLastError());

            return -1;

        }

        // 返回值减去WAIT_OBJECT_0 就是当前有效事件对象的数组序号

        // 如果同时有多个内核对象被触发,函数返回的只是其中序号最小的那个

        Pipe = Ret - WAIT_OBJECT_0;

 

        // 把指定的事件对象设置为无信号状态

        ResetEvent(Event[Pipe]);

 

        // 索检一个异步(重叠)操作实例当前的状态

        // PipeHandles[Pipe] 要索检的管道句柄

        // Ovlap[Pipe] 之前设定的该管道实例的异步结构

        // &BytesTransferred 用于记录该次传输字节数量的一个缓冲区

        // TRUE 指明一直等到异步操作结束才返回;FALSE表示立即返回

        if (GetOverlappedResult(PipeHandles[Pipe], &Ovlap[Pipe],

            &BytesTransferred, TRUE) == 0)

        {

            printf("取得异步操作状态失败或客户端关闭连接,错误代码: %d/n 重新启动该管道实例/n",

                GetLastError());

 

            // 断开当前管道连接

            if (DisconnectNamedPipe(PipeHandles[Pipe]) == 0)

            {

                printf("管道断开失败,错误代码: %d/n",

                    GetLastError());

                return -1;

            }

 

            // 重新开始监听当前管道实例

            if (ConnectNamedPipe(PipeHandles[Pipe], &Ovlap[Pipe]) == 0)

            {

                if (GetLastError() != ERROR_IO_PENDING)

                {

                    printf("管道实例 %d 重启失败,错误代码: %d/n",

                          i, GetLastError());

                    // 关闭失败的管道实例

                    CloseHandle(PipeHandles[Pipe]);

                }

            }

            // 管道实例状态

            DataRead[Pipe] = FALSE;

        }

        // 当取得一个重叠操作状态未发生错误时,则开始读或写操作

        else

        {

            if (DataRead[Pipe] == FALSE)

            {

                // 重设当前异步结构

                ZeroMemory(&Ovlap[Pipe], sizeof(OVERLAPPED));

                Ovlap[Pipe].hEvent = Event[Pipe];

 

                // 读取数据,因异步操作,该函数立刻返回,当读取完毕时,触发事件对象有效

                if (ReadFile(PipeHandles[Pipe], Buffer[Pipe],

                    BUFFER_SIZE, NULL, &Ovlap[Pipe]) == 0)

                {

                    if (GetLastError() != ERROR_IO_PENDING)

                    {

                        printf("读取消息时发生错误,错误代码: %d/n",

                            GetLastError());

                    }

                }

                DataRead[Pipe] = TRUE;

            }

            else

            {

                printf("读取到的数据大小为: %d bytes/n",

                    BytesTransferred);

 

                ZeroMemory(&Ovlap[Pipe], sizeof(OVERLAPPED));

                Ovlap[Pipe].hEvent = Event[Pipe];

 

                // 将读取到的数据返回给客户端

                if (WriteFile(PipeHandles[Pipe], Buffer[Pipe],

                    BytesTransferred, NULL, &Ovlap[Pipe]) == 0)

                {

                    if (GetLastError() != ERROR_IO_PENDING)

                    {

                        printf("发送消息时发生错误,错误代码: %d/n",

                            GetLastError());

                    }

                }

                DataRead[Pipe] = FALSE;

            }

        }

    }      

 

    return 0;

}

 

 

命名管道客户端

 

#pragma once

 

#include <stdio.h>

#include <tchar.h>

#include <windows.h>

 

#define PIPE_NAME TEXT("////.//Pipe//Tc")

#define MyDATE    TEXT("测试。。。测试")

 

 

int _tmain(int argc, _TCHAR* argv[])

{

    HANDLE PipeHandle;

    DWORD  BytesWritten;

 

    // 检查是否存在一个现成的命名管道实例

    // PIPE_NAME 试图与之建立连接的命名管道服务器名称

    // NMPWAIT_WAIT_FOREVER 指定客户机可以等待一个管道进程的时间;

       // 让它在管道上完成一个待决的ConnectNamedPipe操作

       // 该常数表示无限制

    if (WaitNamedPipe(PIPE_NAME, NMPWAIT_WAIT_FOREVER) == 0)

    {

        printf("等待管道连接失败,错误代码: %d/n",

            GetLastError());

        return -1;

    }

 

    // 打开一个管道

    // PIPE_NAME 要打开的命名管道服务器名称

    // GENERIC_READ | GENERIC_WRITE 打开模式,可读可写。该模式需要与服务端兼容

    // 参数三 0 表示不共享;因为一次只能有一个客户机访问一个管道实例

    // (LPSECURITY_ATTRIBUTES) NULL 该参数应设为NULL,除非需要子进程继承客户机的句柄

    // OPEN_EXISTING 管道实例必须已经存在,函数会在管道不存在的情况下调用失败

    // FILE_ATTRIBUTE_NORMAL 默认属性

    // (HANDLE) NULL 它对命名管道无效,应设为NULL

    if ((PipeHandle = CreateFile(PIPE_NAME,

        GENERIC_READ | GENERIC_WRITE, 0,

        (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING,

        FILE_ATTRIBUTE_NORMAL,

        (HANDLE) NULL)) == INVALID_HANDLE_VALUE)

    {

        printf("打开管道失败,错误代码: %d/n", GetLastError());

        return -1;

    }

 

    if (WriteFile(PipeHandle, MyDATE, sizeof(MyDATE), &BytesWritten,

        NULL) == 0)

    {

        printf("发送消息失败,错误代码: %d/n", GetLastError());

        CloseHandle(PipeHandle);

        return -1;

    }

 

    printf("发送消息数量为: %d bytes", BytesWritten);

 

    CloseHandle(PipeHandle);

 

    return 0;

}

原创粉丝点击