进程间通信-命名管道


  • 命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。我们在不了解网络协议的情况下,也可以利用命名管道来实现进程间的通信。

  • 命名管道充分利用了Windows NT和Windows 2000内建的安全机制。

  • 将命名管道作为一种网络编程方案时,它实际上建立了一个客户机/服务器通信体系,并在其中可靠地传输数据。

  • 命名管道是围绕Windows文件系统设计的一种机制,采用“命名管道文件系统(Named Pipe File System,NPFS)”接口,因此,客户机和服务器可利用标准的Win32文件系统函数(例如:ReadFile和WriteFile)来进行数据的收发。

  • 命名管道服务器和客户机的区别在于:服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。而客户机只能同一个现成的命名管道服务器建立连接。

  • 命名管道服务器只能在Windows NT或Windows 2000上创建,所以,我们无法在两台Windows 95或Windows 98计算机之间利用管道进行通信。不过,客户机可以是Windows 95或Windows 98计算机,与Windows NT或Windows 2000计算机进行连接通信。

  • 命名管道提供了两种基本通信模式:字节模式和消息模式。在字节模式中,数据以一个连续的字节流的形式,在客户机和服务器之间流动。而在消息模式中,客户机和服务器则通过一系列不连续的数据单位,进行数据的收发,每次在管道上发出了一条消息后,它必须作为一条完整的消息读入。


①HANDLE CreateNamedPipe (
  LPCTSTR lpName,         // pointer to pipe name
  DWORD dwOpenMode,       // pipe open mode
  DWORD dwPipeMode,       // pipe-specific modes
  DWORD nMaxInstances,    // maximum number of instances
  DWORD nOutBufferSize,   // output buffer size, in bytes
  DWORD nInBufferSize,    // input buffer size, in bytes
  DWORD nDefaultTimeOut,  // time-out time, in milliseconds
  LPSECURITY_ATTRIBUTES lpSecurityAttributes  // pointer to security attributes
);


(The CreateNamedPipe function creates an instance of a named pipe and returns a handle for subsequent pipe operations. A named pipe server process uses this function either to create the first instance of a specific named pipe and establish its basic attributes or to create a new instance of an existing named pipe. If the function succeeds, the return value is a handle to the server end of a named pipe instance. If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError. The return value is ERROR_INVALID_PARAMETER if nMaxInstances is greater than  PIPE_UNLIMITED_INSTANCES.)


lpName
Pointer to the null-terminated string that uniquely identifies the pipe. The string must have the following form:
\\.\pipe\pipename
以\\开始,这里 . 表示本地机器,,如果用连接到远程机器则需要填写远程主机得名字,pipe是pipe硬编码,不用修改,直接填pipe就可以了,pipename是创建的管道的名字。


nDefaultTimeOut
Specifies the default time-out value, in milliseconds, if the WaitNamedPipe function specifies NMPWAIT_USE_DEFAULT_WAIT. Each instance of a named pipe must specify the same value.

 

 

②BOOL ConnectNamedPipe (
  HANDLE hNamedPipe,          // handle to named pipe to connect
  LPOVERLAPPED lpOverlapped   // pointer to overlapped structure
);


(The ConnectNamedPipe function enables a named pipe server process to wait for a client process to connect to an instance of a named pipe. A client process connects by calling either the CreateFile or CallNamedPipe function. If the function succeeds, the return value is nonzero.If the function fails, the return value is zero. To get extended error information, call GetLastError.)
注意这个函数的名字容易引起歧义,仔细参见函数说明。这里参数lpOverlapped是有用的。

 

 

③typedef struct _OVERLAPPED { // o
    DWORD  Internal;
    DWORD  InternalHigh;
    DWORD  Offset;
    DWORD  OffsetHigh;
    HANDLE hEvent;
} OVERLAPPED;


hEvent
Handle to an event set to the signaled state when the transfer has been completed. The calling process sets this member before calling the ReadFile, WriteFile, ConnectNamedPipe, or TransactNamedPipe function.

 

 

④BOOL WaitNamedPipe(
  LPCTSTR lpNamedPipeName,  // pointer to name of pipe for which to wait
  DWORD nTimeOut            // time-out interval, in milliseconds
);


(The WaitNamedPipe function waits until either a time-out interval elapses or an instance of the specified named pipe is available to be connected to (that is, the pipe’s server process has a pending ConnectNamedPipe operation on the pipe)).


lpNamedPipeName
Pointer to a null-terminated string that specifies the name of the named pipe. The string must include the name of the computer on which the server process is executing. A period may be used for the servername if the pipe is local. The following pipe name format is used:
\\servername\pipe\pipename

 

 


Eg:
服务端:

void CNamedPipeSrvView::OnPipeCreate()
{
 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())
  {
   MessageBox(“等待客户端连接失败!”);
   CloseHandle(hPipe);
   CloseHandle(hEvent);
   hPipe=NULL;
   return;
  }
 }
 if(WAIT_FAILED==WaitForSingleObject(hEvent,INFINITE))
 {
  MessageBox(“等待对象失败!”);
  CloseHandle(hPipe);
  CloseHandle(hEvent);
  hPipe=NULL;
  return;
 }
 CloseHandle(hEvent);
}

void CNamedPipeSrvView::OnPipeRead()
{
 char buf[100];
 DWORD dwRead;
 if(!ReadFile(hPipe,buf,100,&dwRead,NULL))
 {
  MessageBox(“读取数据失败!”);
  return;
 }
 MessageBox(buf);
}

void CNamedPipeSrvView::OnPipeWrite()
{
 char buf[]=”Hello named pipe!”;
 DWORD dwWrite;
 if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
 {
  MessageBox(“写入数据失败!”);
  return;
 }
}

 

 

 

 

 

 

 

 

 

客户端:
void CNamedPipeCltView::OnPipeConnect()
{
 if(!WaitNamedPipe(“\\\\.\\pipe\\MyPipe”,NMPWAIT_WAIT_FOREVER))
 {
  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;
 }
}

void CNamedPipeCltView::OnPipeRead()
{
 char buf[100];
 DWORD dwRead;
 if(!ReadFile(hPipe,buf,100,&dwRead,NULL))
 {
  MessageBox(“读取数据失败!”);
  return;
 }
 MessageBox(buf);
}

void CNamedPipeCltView::OnPipeWrite()
{
 char buf[]=”命名管道测试程序”;
 DWORD dwWrite;
 if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
 {
  MessageBox(“写入数据失败!”);
  return;
 }
}




Modified At 2008-03-27 20:52:48

Leave a Reply

Your email address will not be published.