• 命名管道和油槽


    我们接着简绍2种进程间通信的方法:
    3.命名管道:
    命名管道可以再2个任意进程间通信(包括网络上的2个不同主机之上的进程) 他们建立了如客户机/服务器的连接
    创建命名通道的机器为服务器 连接命名通道的机器为客户机
    在命名管道的使用中 我们会使用事件对象来标识管道的连接和读写操作
    下面是要用到的函数:(有关详细简绍可以看msdn)

    这个函数用来创建一个命名管道 失败则返回INVALID_HANDLE_VALUE 成功返回管道句柄
    HANDLE CreateNamedPipe(
      LPCTSTR lpName,                             // pipe name
      DWORD dwOpenMode,                           // pipe open mode
      DWORD dwPipeMode,                           // pipe-specific modes//
      DWORD nMaxInstances,                        // maximum number of instances
      DWORD nOutBufferSize,                       // output buffer size
      DWORD nInBufferSize,                        // input buffer size
      DWORD nDefaultTimeOut,                      // time-out interval
      LPSECURITY_ATTRIBUTES lpSecurityAttributes  // SD
    );

    这个函数用来等待客户机的连接
    BOOL ConnectNamedPipe(
      HANDLE hNamedPipe,          // handle to named pipe
      LPOVERLAPPED lpOverlapped   // overlapped structure
    );

    这个函数用来连接命名管道(客户机使用)
    BOOL WaitNamedPipe(
      LPCTSTR lpNamedPipeName,  // pipe name
      DWORD nTimeOut            // time-out interval
    );

    大致流程如下:

    创建命名管道(CreateNamedPipe)--------------->创建事件对象(CreateEvent)------->利用OVERLAPPED结构体关联管道和事件对象------------------>调用

    ConnectNamedPipe等待连接------->调用WaitForSingleObject函数等待事件对象发生

    --------------------------------------------------------------代码如下
    HANDLE hPipe;
    hPipe=CreateNamedPipe("////.//pipe//Mypipe",  //在程序中药输出/输入'/'这要输入'//' 一个代表转义
      PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,0,1,1024,1024,0,NULL);//创建命名管道
    if (INVALID_HANDLE_VALUE==hPipe)
    {
      MessageBox("创建命名管道失败!");
      hPipe=NULL;
      return;
    }

    HANDLE hEvent;
    hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
    if (!hEvent)
    {
      MessageBox("创建事件对象失败!");
      CloseHandle(hPipe);
      hPipe=NULL;
      return;
    }

    OVERLAPPED ovlap;
    ZeroMemory(&ovlap,sizeof(OVERLAPPED));//把这个结构体中无关的数据成员全部清零
    ovlap.hEvent=hEvent;
    if (!ConnectNamedPipe(hPipe,&ovlap))
    {
      if (ERROR_IO_PENDING!=GetLastError())//我们采用的是重复模式
      { //在IO操作未完成的时候函数就返回了 转到后台执行 所以要判断是否失败要调用GetLastError()
       MessageBox("等待客服端连接失败!");
       CloseHandle(hEvent);
       CloseHandle(hPipe);
       hEvent=NULL;
       hPipe=NULL;
       return;
      }
    }
    /////等待事件发生 当有事件发生时说明有客户端连接到命名管道了
    if(WAIT_FAILED==WaitForSingleObject(hEvent,INFINITE)){
      MessageBox("等待对象失败!");
      CloseHandle(hEvent);
      CloseHandle(hPipe);
      hEvent=NULL;
      hPipe=NULL;
      return;
    }
    CloseHandle(hEvent);

    -----------------------------------------客户机连接到命名管道

    if(!WaitNamedPipe("////.//pipe//Mypipe",NMPWAIT_USE_DEFAULT_WAIT)){
      MessageBox("当前没有可利用的命名管道实例!");
      return;
    }
    hPipe=CreateFile("////.//pipe//Mypipe",
      GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if ( INVALID_HANDLE_VALUE==hPipe)
    {
      MessageBox("打开命名管道失败!");
      hPipe=NULL;
      return;
    }


    --------------------------------------------读文件
    char buf[100];
    DWORD dwRead;//实际读取数据数目
    //读取数据
    if (!ReadFile(hPipe,buf,100,&dwRead,NULL))
    {
      MessageBox("读取数据失败!");
    }
    MessageBox(buf);


    ---------------------------------------------写文件
    char buf[]="客户端写入数据";
    DWORD dwWrite;//实际写入的数据量
    //写入数据
    if (!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
    {
      MessageBox("写入数据失败!");
    }

    4.油槽
    也可以像命名管道一样用于任意进程间通信 但要注意的是 油槽的创建者进程只能从油槽中读取数据 使用者进程只能写入数据
    如果要实现双向通信 只需要建立2个油槽 油槽是基于广播通信的 这样我们可以用很少的代码实现广播  实现1对多的单向通信 才用socket编码则较为复杂 缺点是发送数据量较

    少 消息大小为424字节以下

    油槽创建比较简单,下面是源代码:

    ////////////////////////////////////////////创建油槽 创建者进城 读取数据
    HANDLE hMailSlot;
    hMailSlot=CreateMailslot("////.//mailslot//MyMalislot",
      0,MAILSLOT_WAIT_FOREVER,NULL);
    if (INVALID_HANDLE_VALUE==hMailSlot)
    {
      MessageBox("油槽创建失败!");
      CloseHandle(hMailSlot);
      return;
    }

    char buf[100];
    DWORD dwRead;//实际读取数据数目
    //读取数据
    if (!ReadFile(hMailSlot,buf,100,&dwRead,NULL))
    {
      MessageBox("读取数据失败!");
    }
    MessageBox(buf);
    CloseHandle(hMailSlot);

    //////////////////////////////////////////使用者进程  写入数据

    HANDLE hMailslot;
    hMailslot=CreateFile("////.//mailslot//MyMalislot",GENERIC_WRITE,
      FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if (hMailslot==INVALID_HANDLE_VALUE)
    {
      MessageBox("打开油槽失败!");
      return;
    }

    char buf[]="油槽写入数据";
    DWORD dwWrite;//实际写入的数据量
    //写入数据
    if (!WriteFile(hMailslot,buf,strlen(buf)+1,&dwWrite,NULL))
    {
      MessageBox("写入数据失败!");
      CloseHandle(hMailslot);
    }

    CreateFile WriteFile ReadFile可以用来创建,读取文件 也能用来创建,读取油槽 命名管道等 见MSDN

  • 相关阅读:
    vue报错:Not Found
    使用Vue DevTools 插件报错的问题:Vue.js is detected on this page. Open DevTools and look for the Vue panel.
    Linux安装docker
    asp.net5.0源码(Microsoft github源码)
    探索Asp net core3中的 项目文件、Program.cs和通用host(转)
    c#中的sealed关键字
    .NET平台常见技术框架整理汇总
    疫情下孩子的网课
    常系数齐次线性递推
    【2021~2022】模拟赛乱写 Period I
  • 原文地址:https://www.cnblogs.com/liyuanjinglyj/p/4656621.html
Copyright © 2020-2023  润新知