ACE_Select_Reactor 之 管道通信 Pipe

ACE_Select_Reactor 基于ACE_Pipe实现,为此了解了下Pipe通信编程

命名管道的连接和通讯采用如下方式:  
   
          *   在服务器端第一次创建命名管道后等待连接,当客户端连接成功后服务器端的命名管道就用作通讯用途。如果需要再次等待连接,服务器端就需要再次打开命名管道(创建一个命名管道的实例)并等待连接。  
          *   对于客户端每次打开命名管道后建立与服务器间的连接,然后就可以利用命名管道进行通信,如果需要建立第二个连接则需要再次打开管道和再次建立连接。    
   
  创建命名管道时需要指定一个主机名和管道名,对于客户端来说可以是如下格式://[host_name]/pipe/[pipe_name]/也可以是//./pipe/pipe_name/其中.表示本机。而服务器端只能够在指定本机作为主机名,即只能使用下面的格式://./pipe_name   /。此外需要记住,在同一主机上管道名称是唯一的,一个命名管道一旦被创建就不允许相同名称的管道再被创建。  
   
  服务器方通过:  
   
  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  
  );  
   
  创建命名管道和打开已经存在的命名管道,其中lpName为管道名称,dwOpenMode为创建方式,可以是下面值的组合:  
   
          *   PIPE_ACCESS_INBOUND:管道只能用作接收数据。  
          *   PIPE_ACCESS_OUTBOUND:管道只能用作发送数据。  
          *   PIPE_ACCESS_DUPLEX:管道既可以发送也可以接收数据。(上面这三个值只能够取其中一个)  
          *   FILE_FLAG_WRITE_THROUGH:管道用于同步发送和接收数据,只有在数据被发送到目标地址时发送函数才会返回,如果不设置这个参数那么在系统内部对于命名管道的处理上可能会因为减少网络附和而在数据积累到一定量时才发送,并且对于发送函数的调用会马上返回。  
          *   FILE_FLAG_OVERLAPPED:管道可以用于异步输入和输出,异步读写的有关方法和文件异步读写是相同的。    
   
  dwPipeMode指定管道类型,可以是下面值的组合:  
   
          *   PIPE_TYPE_BYTE:数据在通过管道发送时作为字节流发送,不能与PIPE_READMODE_MESSAGE共用。  
          *   PIPE_TYPE_MESSAGE:数据在通过管道发送时作为消息发送,不能与PIPE_READMODE_BYTE共用。  
          *   PIPE_READMODE_BYTE:在接收数据时接收字节流。  
          *   PIPE_READMODE_MESSAGE:在接收数据时接收消息。  
          *   PIPE_WAIT:使用等待模式,在读,写和建立连接时都需要管道的另一方完成相应动作后才会返回。  
          *   PIPE_NOWAIT:使用非等待模式,在读,写和建立连接时不需要管道的另一方完成相应动作后就会立即返回。    
   
  nMaxInstances为管道的的最大数量,在第一次建立服务器方管道时这个参数表明该管道可以同时存在的数量。   PIPE_UNLIMITED_INSTANCES表明不对数量进行限制。nOutBufferSize和nInBufferSize表示缓冲区的大小。   nDefaultTimeOut表示在等待连接时最长的等待时间(以毫秒为单位),如果在创建时设置为NMPWAIT_USE_DEFAULT_WAIT   表明无限制的等待,而以后服务器方的其他管道实例也需要设置相同的值。lpSecurityAttributes为安全属性,一般设置为NULL。如果创建或打开失败则返回INVALID_HANDLE_VALUE。可以通过GetLastError得到错误。  
   
  客户方通过:  
   
  HANDLE   CreateFile(  
      LPCTSTR   lpFileName,                                                   //   file   name  
      DWORD   dwDesiredAccess,                                             //   access   mode  
      DWORD   dwShareMode,                                                     //   share   mode  
      LPSECURITY_ATTRIBUTES   lpSecurityAttributes,   //   SD  
      DWORD   dwCreationDisposition,                                 //   how   to   create  
      DWORD   dwFlagsAndAttributes,                                   //   file   attributes  
      HANDLE   hTemplateFile                                                 //   handle   to   template   file  
  );  
   
  创建客户端命名管道,CreateFile可以有很多用途,可以用来创建文件,管道,邮件槽,目录等,这里介绍用CreateFile来打开客户端命名管道。lpFileName用来指明管道名称。dwDesiredAccess用来表明使用方式,可以使用下面的值:  
   
          *   GENERIC_READ:打开一个只用于读的管道。  
          *   GENERIC_WRITE:打开一个只用于写的管道。  
          *   GENERIC_READ   |   GENERIC_WRITE:打开一个用于读和写的管道。    
   
  dwShareMode指定共享方式,一般指定为0,lpSecurityAttributes为安全属性,一般设置为NULL,   dwCreationDisposition设置为OPEN_EXISTING,dwFlagsAndAttributes设置为   FILE_ATTRIBUTE_NORMAL,此外可以还设置为FILE_FLAG_OVERLAPPED来进行异步通讯,hTemplateFile设置为NULL。如果打开失败则返回INVALID_HANDLE_VALUE。可以通过GetLastError得到错误。  
   
  此外客户方可以利用:  
   
  BOOL   CallNamedPipe(  
      LPCTSTR   lpNamedPipeName,     //   pipe   name  
      LPVOID   lpInBuffer,                 //   write   buffer  
      DWORD   nInBufferSize,             //   size   of   write   buffer  
      LPVOID   lpOutBuffer,               //   read   buffer  
      DWORD   nOutBufferSize,           //   size   of   read   buffer  
      LPDWORD   lpBytesRead,             //   number   of   bytes   read  
      DWORD   nTimeOut                         //   time-out   value  
  );  
   
  来创建一个发送消息的管道。  
   
  管道的连接管理,客户方在调用CreateFile后立即就能够建立服务器的连接,而服务器方一旦管道打开或创建后可以用  
   
  BOOL   ConnectNamedPipe(  
      HANDLE   hNamedPipe,                     //   handle   to   named   pipe  
      LPOVERLAPPED   lpOverlapped       //   overlapped   structure  
  );  
   
  来等待客户端的连接建立。如果希望在服务器方检测是否有连接到达,可以调用  
   
  BOOL   WaitNamedPipe(  
      LPCTSTR   lpNamedPipeName,     //   pipe   name  
      DWORD   nTimeOut                         //   time-out   interval  
  );  
   
  这里的lpNamePipeName直接使用创建管道时的名称,如果在服务器方希望关闭连接则调用  
   
  BOOL   DisconnectNamedPipe(  
      HANDLE   hNamedPipe       //   handle   to   named   pipe  
  );  
   
  一旦连接被关闭,服务器方可以再次调用ConnectNamedPipe来建立连接。如果要关闭管道则直接调用CloseHandle。请注意这里提到的关闭管道和关闭连接是不同的意思,在同一个管道上可以依次反复建立连接,而且可以减小系统的负荷。而且如果指定了管道最大数量限制那么在打开的管道达到最大限制后如果不关闭旧管道就无法打开新管道。  
   
  对于客户方则无法关闭连接,而只能直接调用CloseHandle关闭管道。  
   
  数据的发送,不论是服务器还是客户方都可以通过ReadFile和WriteFile进行管道读写来达到通讯的目的。  
   
  下面是一个例子,服务器方创建或打开一个管道并读入对方发送的数据,将小写字母转换成大写字母后返回,而客户发创建一个到服务器的连接并发送一个字符串并读回经过转换的数据:  
   
  在使用这个例子时,运行三个服务端进程,而运行第四个时会因为达到管道数量限制而打开管道失败。

// PipeServer.cpp : Defines the entry point for the console application.
// 管道通信服务器

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwErr = 0;
DWORD dwTime = NMPWAIT_USE_DEFAULT_WAIT;

//  创建管道
HANDLE hPipe = CreateNamedPipe(".//pipe//socket_pipe//", 
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE,
3,
256,
256,
dwTime,
NULL);

if ( INVALID_HANDLE_VALUE == hPipe )
{
dwErr = GetLastError();

printf("CreateNamePipe Error");
return 0;
}

printf("Waiting For Pipe Connect.../r/n");

// 等待管道链接
if ( !ConnectNamedPipe( hPipe, NULL ) )
{
CloseHandle( hPipe );

dwErr = GetLastError();

printf("ConnectNamedPipe Error");
return 0;
}

BYTE bRead;
DWORD dwRead, dwWriten;

printf("ReadFile From Pipe .../r/n");

// 读写管道文件
while ( ReadFile( hPipe, &bRead, 1, &dwRead, NULL ) )
{
if ( bRead >= 'a' && bRead <= 'z' )
bRead = 'A' + (bRead - 'a');

WriteFile( hPipe, &bRead, 1, &dwWriten, NULL );
}

CloseHandle( hPipe );


return 0;
}



// PipeClient.cpp : Defines the entry point for the console application.
// 管道通信客服端

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwErr = 0;

HANDLE hClient = CreateFile( ".//pipe//socket_pipe//",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if ( INVALID_HANDLE_VALUE == hClient )
{
dwErr = GetLastError();
printf("CreateFile Error");

return 0;
}


// 发送数据(写文件)
DWORD dwRead, dwWriten;
char szSend[256] = "Ya Tou Xin Ku le, Wei Le Ni Nu Li";
char szRecv[256];

for ( int i = 0; i < (strlen(szSend)+1); i++ )
{
WriteFile( hClient, szSend + i, 1, &dwWriten, NULL );

ReadFile( hClient, szRecv+i, 1, &dwRead, NULL );
}

cout << "Recv: " << szRecv << endl;

CloseHandle( hClient );

return 0;
}

        // 可以将上面的例子进行扩展,使用线程来等待Pipe的链接,链接上之后使用一个新的线程来管理这个Pipe进行通信
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值