用命名管道实现进程间的通信:
命名管道概念:
命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。我们在不了解网络协议的情况下,也可以利用命名管道来实现进程间的通信。
命名管道充分利用了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
允许重叠模式。如果采用了重叠模式,那么那些读写和连接操作可能要花一段时间才能完成的函数会立即返回。
在重叠模式下,前台线程可以执行其他操作,而费时的操作可以放到后台执行。如果不是重叠模式,则读写以及连接操作直到完成之后函数才会返回。
ReadFileEx 和
WriteFileEx
函数只有在重叠模式下才会使用管道句柄;而
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.
-
Value |
Meaning |
NMPWAIT_USE_DEFAULT_WAIT |
The time-out interval is the default value specified by the server process in the CreateNamedPipe function. |
NMPWAIT_WAIT_FOREVER |
The 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