孙鑫VC学习笔记:第十七讲 (三) 用命名管道实现进程间的通信

来源:互联网 发布:软件代理商的盈利模式 编辑:程序博客网 时间:2024/05/17 01:58
用命名管道实现进程间的通信:
 
命名管道概念:
命名管道是通过网络来完成进程间的通信,它屏蔽了地称的网络协议细节。我们在不了解网络协议的情况下,也可以利用命名管道来实现进程间的通信。
命名管道充分利用了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 OVERLAPPEDstructure should contain a handle to a manual-reset event object (which the server can create by using the CreateEventfunction).
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;
 
原创粉丝点击