孙鑫MFC笔记教程(17)--进程间通信2(命名管道)

用命名管道实现进程间的通信:
 
命名管道概念:
命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。我们在不了解网络协议的情况下,也可以利用命名管道来实现进程间的通信。
命名管道充分利用了Windows NT和Windows2000内建的安全机制。
将命名管道作为一种网络编程方案时,它实际上建立了一个客户机/服务器通信体系,并在其中可靠的传输数据。
命名管道是围绕Windows文件系统设计的一种机制,采用“命名管道文件系统(Named Pipe File System,NPFS)”接口,因此,客户机和服务器可利用标准的Win32文件系统内核(例如ReadFile和WriteFile)来进行数据的收发。
命名管道服务器和客户机的区别在于:服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。而客户机只能同一个现成的命名管道服务器建立连接。
命名管道服务器只能在Windows NT或Windows2000上创建,所以,我们无法在两台Windows95或Windows98计算机之间利用管道进行通信。不过,客户机可以是Windows95或Windows98计算机,与Windows NT或Windows2000计算机进行连接通信。
命名管道提供了两种基本通信模式:字节模式和消息模式。在字节模式中,数据以一个连续的字节流的形式,在客户机和服务器之间流动。而在消息模式中,客户机和服务器则通过一系列不连续的数据单位,进行数据的收发,每次在管道上发出一条消息后,它必须作为一条完整的消息读入。
 
---------------------------------------------------------------------------------
 
服务器进程使用 HANDLE CreateNamedPipe 创建指定命名管道的第一个实例,或现有命名管道的新的实例,并建立它的基本属性。多次调用本函数可以创建多个命名管道实例。
CreateNamedPipe
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.
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
);
Windows Me/98/95: Named pipes cannot be created.
 
Parameters
lpName
Pointer to the null-terminated string that uniquely identifies the pipe. The string must have the following form 字符串必须是下面的格式:
//./pipe/pipename中间的点表示本地机器, pipe 不可以改变, pipename 是管道名)
如果要与远程的机器连接,需要将中间的点设置为远程服务器的名字
The pipename part of the name can include any character other than a backslash, including numbers and special characters. The entire pipe name string can be up to 256 characters long. Pipe names are not case sensitive.
Pipe 不可以改变,但是大小写无所谓。
dwOpenMode
Specifies the pipe access mode (访问方式) , the overlapped mode, the write-through mode, and the security access mode of the pipe handle.
管道的每个实例都必须要有同样的访问方式,其值可以是下面值:
Mode
PIPE_ACCESS_DUPLEX
表明管道是双向的,服务器和客户端进程都可以从管道读取或者向管道写入数据。服务器上指定该模式等价于
GENERIC_READ | GENERIC_WRITE
 
PIPE_ACCESS_INBOUND
在管道中的数据从客户端向服务器端流动,
相当于服务器端(只读)用GENERIC_READ 访问管道,
而客户端(只写)必须指定GENERIC_WRITE 访问
 
PIPE_ACCESS_OUTBOUND
与上面的值效果相反,服务器端只能写入数据,客户端只能读取数据
也可包含下面值的一个或者全部
FILE_FLAG_WRITE_THROUGH       
FILE_FLAG_OVERLAPPED
允许重叠模式。如果采用了重叠模式,那么那些读写和连接操作可能要花一段时间才能完成的函数会立即返回。
在重叠模式下,前台线程可以执行其他操作,而费时的操作可以放到后台执行。如果不是重叠模式,则读写以及连接操作直到完成之后函数才会返回。
ReadFileExWriteFileEx 函数只有在重叠模式下才会使用管道句柄;而 ReadFile, WriteFile, ConnectNamedPipe, 以及 TransactNamedPipe 可以同步方式也可以重叠方式读写。
 
dwPipeMode 指定是创建一个字节模式还是消息模式的管道。
Specifies the type, read, and wait modes of the pipe handle.
One of the following type mode flags can be specified. The same type mode must be specified for each instance of the pipe. 管道的每一个实例都要指定同样的实例。If you specify zero, the parameter defaults to byte-type mode.
Mode
Description
PIPE_TYPE_BYTE
Data is written to the pipe as a stream
of bytes.
该模式下不能与 PIPE_READMODE_MESSAGE 一直使用。
因为对于字节模式的命名管道,数据是以字节流发送数据,没有定界符,这里如果采用PIPE_READMODE_MESSAGE 就会不知道要读多少字节。
 
PIPE_TYPE_MESSAGE
Data is written to the pipe as a stream
of messages .
这种模式可以与PIPE_READMODE_MESSAGE 或
PIPE_READMODE_BYTE 组合使用.
在消息模式下发送消息时,会有一个定界符,
如果以PIPE_READMODE_MESSAGE 模式去读的话,
通过一个定界符可以读到完整的消息。而采用PIPE_TYPE_BYTE 读方式将忽略定界符,直接读取数据。
 
 
Remarks
To create an instance of a named pipe by using CreateNamedPipe, the user must have FILE_CREATE_PIPE_INSTANCE access to the named pipe object. If a new named pipe is being created, the access control list (ACL) from the security attributes parameter defines the discretionary access control for the named pipe.
All instances of a named pipe must specify the same pipe type (byte-type or message-type), pipe access (duplex, inbound, or outbound), instance count, and time-out value. If different values are used, this function fails and GetLastError returns ERROR_ACCESS_DENIED.
The input and output buffer sizes are advisory. The actual buffer size reserved for each end of the named pipe is either the system default, the system minimum or maximum, or the specified size rounded up to the next allocation boundary.
The pipe server should not perform a blocking read operation until the pipe client has started. Otherwise, a race condition can occur. This typically occurs when initialization code, such as the C run-time, needs to lock and examine inherited handles.
An instance of a named pipe is always deleted when the last handle to the instance of the named pipe is closed.
Return Values
If the function succeeds, the return value is a handle to the server end of a named pipe instance.
---------------------------------------------------------------------------------
ConnectNamedPipe
允许一个命名管道服务器进程等待一个客户端进程连接到一个命名管道的实例上。
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.
BOOL ConnectNamedPipe(
HANDLE
hNamedPipe ,       // handle to named pipe to connect
LPOVERLAPPED lpOverlapped // pointer to overlapped structure
);
Parameters
hNamedPipe
[in] Handle to the server end of a named pipe instance. This handle is returned by the CreateNamedPipe function.
lpOverlapped
[in] Pointer to an OVERLAPPED structure.
If hNamedPipe was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must not be NULL. It must point to a valid OVERLAPPED structure . If hNamedPipe was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function can incorrectly report that the connect operation is complete.
If hNamedPipe was created with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the OVERLAPPED structure should contain a handle to a manual-reset event object (which the server can create by using the CreateEvent function).
If hNamedPipe was not opened with FILE_FLAG_OVERLAPPED, the function does not return until a client is connected or an error occurs. Successful synchronous operations result in the function returning a nonzero value if a client connects after the function is called.

Return Values
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.
 
如果ConnectNamedPipe返回一个零值
而ERROR_IO_PENDING= =GetLastError()表示这个操作没有失败,
可能在随后的时间内这个操作会完成
 
 
OVERLAPPED
The OVERLAPPED structure contains information used in asynchronous input and output (I/O).
typedef struct _OVERLAPPED { // o
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
Members
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.
 
---------------------------------------------------------------------------------
用命名管道实现进程间通信的实例:
首先编写服务器端程序,步骤如下:
1.新建一个单文档程序NamedPipSrv
2.添加一个“命名管道”子菜单和“创建管道”、“读取数据”、“写入数据”菜单项
3.为CNamedPipeSrvView添加变量:HANDLE hPipe;
1)创建命名管道
2)创建一个事件对象
3)调用ConnectNamedPipe等待客户端连接请求到来
 
4)读取与写入操作,代码如下:
---------------------------------------------------------------------------------
接着编写客户端程序:
1.新建一个项目NamedPipeClt添加到当前工作区
2.增加“命名管道”子菜单以及“连接管道”、“读取数据”与“写入数据”两个菜单项。
3.为CNamedPipeCltView 添加变量:HANDLE hPipe;

 

//WaitNamePipe的参数NMPWAIT_WAIT_FOREVER一直等待下去,直到等待到可用的连接,当然也可以设置超时的时间,但前提是所有的程序里所有的命名管道的超时时间必须一样

       if(!WaitNamedPipe(".//pipe//MyPipe",NMPWAIT_WAIT_FOREVER))  //程序中的反斜杠若要输出两个则需要4个

      {

           MessageBox("当前没有可用的命名管道实例");

           return;

      }

      //打开命名管道,建立连接

      hPipe=CreateFile("127.0.0.1//pipe//MyPipe",GENERIC_READ|GENERIC_WRITE, 0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

      if(INVALID_HANDLE_VALUE==hPipe)

      {

           MessageBox("打开命名管道失败!");

           hPipe=NULL;

}

WaitNamedPipe

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

BOOL WaitNamedPipe(
  LPCTSTR lpNamedPipeName,  // pipe name
  DWORD nTimeOut            // time-out interval
);
Parameters
lpNamedPipeName
[in] 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

nTimeOut
[in] Specifies the number of milliseconds that the function will wait for an instance of the named pipe to be available. You can used one of the following values instead of specifying a number of milliseconds.
ValueMeaning
NMPWAIT_USE_DEFAULT_WAITThe time-out interval is the default value specified by the server process in the CreateNamedPipe function.
NMPWAIT_WAIT_FOREVERThe function does not return until an instance of the named pipe is available.
Return Values

If an instance of the pipe is available before the time-out interval elapses, the return value is nonzero.

If an instance of the pipe is not available before the time-out interval elapses, the return value is zero. To get extended error information, call GetLastError.

Remarks

If no instances of the specified named pipe exist, the WaitNamedPipe function returns immediately, regardless of the time-out value.

If the function succeeds, the process should use the CreateFile function to open a handle to the named pipe. A return value of TRUE indicates that there is at least one instance of the pipe available. A subsequent CreateFile call to the pipe can fail, because the instance was closed by the server or opened by another client.  

 

CreateFile

The CreateFile function creates or opens the following objects and returns a handle that can be used to access the object:

  • Consoles
  • Communications resources
  • Directories (open only)
  • Disk devices (Windows NT/2000 only)
  • Files
  • Mailslots
  • Pipes
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用于复制文件句柄
);

 

  参数列表 
  lpFileName String 要打开的文件的名字
  dwDesiredAccess Long 如果为 GENERIC_READ 表示允许对设备进行读访问;如果为 GENERIC_WRITE 表示允许对设备进行写访问(可组合使用);如果为零,表示只允许获取与一个设备有关的信息
  dwShareMode Long, 零表示不共享; FILE_SHARE_READ 和/或 FILE_SHARE_WRITE 表示允许对文件进行共享访问
  lpSecurityAttributes SECURITY_ATTRIBUTES, 指向一个SECURITY_ATTRIBUTES结构的指针,定义了文件的安全特性(如果操作系统支持的话)
  dwCreationDisposition Long,下述常数之一:
  CREATE_NEW 创建文件;如文件存在则会出错
  CREATE_ALWAYS 创建文件,会改写前一个文件
  OPEN_EXISTING 文件必须已经存在。由设备提出要求
  OPEN_ALWAYS 如文件不存在则创建它
  TRUNCATE_EXISTING 讲现有文件缩短为零长度
  dwFlagsAndAttributes Long, 一个或多个下述常数
  FILE_ATTRIBUTE_ARCHIVE 标记归档属性
  FILE_ATTRIBUTE_COMPRESSED 将文件标记为已压缩,或者标记为文件在目录中的默认压缩方式
  FILE_ATTRIBUTE_NORMAL 默认属性
  FILE_ATTRIBUTE_HIDDEN 隐藏文件或目录
  FILE_ATTRIBUTE_READONLY 文件为只读
  FILE_ATTRIBUTE_SYSTEM 文件为系统文件
  FILE_FLAG_WRITE_THROUGH 操作系统不得推迟对文件的写操作
  FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作
  FILE_FLAG_NO_BUFFERING 禁止对文件进行缓冲处理。文件只能写入磁盘卷的扇区块
  FILE_FLAG_RANDOM_ACCESS 针对随机访问对文件缓冲进行优化
  FILE_FLAG_SEQUENTIAL_SCAN 针对连续访问对文件缓冲进行优化
  FILE_FLAG_DELETE_ON_CLOSE 关闭了上一次打开的句柄后,将文件删除。特别适合临时文件
  也可在Windows NT下组合使用下述常数标记:
  SECURITY_ANONYMOUS, SECURITY_IDENTIFICATION, SECURITY_IMPERSONATION, SECURITY_DELEGATION, SECURITY_CONTEXT_TRACKING, SECURITY_EFFECTIVE_ONLY
  hTemplateFile Long, 如果不为零,则指定一个文件句柄。新文件将从这个文件中复制扩展属性

返回值

  如执行成功,则返回文件句柄。
  INVALID_HANDLE_VALUE表示出错,会设置GetLastError。即使函数成功,但若文件存在,且指定了CREATE_ALWAYS 或 OPEN_ALWAYS,GetLastError也会设为ERROR_ALREADY_EXISTS
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值