"网络编程"学习(4):命名管道
命名管道在数据的安全访问上发挥着自己的作用。
UNC:Universal naming convention(普遍的命名规则)。LPCTSTR类型
通讯模式:
(1)字节模式,消息是以连续的字节流的形式,在客户机与服务器之间流动。缺点,在一个时间段里,我们将不知道有多少字节从管道中流通。
(2)消息模式,一个完整的数据段,要整读整写。
用Microsoft Visual C++构建一个命名管道或服务器应用程序时,必须在自己的程序文件中加入Winbase.h这个头文件。而且必需与kernel32.lib建立连接。用visual C ++ 的链接器可以配置kernel.lib链接库。
错误返回:
所有Win32 API函数(CreateFile和CreateNamedPipe除外)都会在调用失败的前提下返回0值。CreateFile和CreateNamedPipe返回的则是INVALID_HANDL E_VALUE。
句柄的确切含义: 句柄,实际都是一个整数。它标识一种资源,如窗口、位图等等。就象找一个人,必须知道他(她)的地址一样,如果要操作一种资源,必须先获得句柄。
句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。从数据类型上来看它只是一个16位的无符号整数。应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。在WINDOWS编程中会用到大量的句柄,比如:HINSTANCE(实例句柄),HBITMAP(位图句柄),HDC(设备描述表句柄),HICON(图标句柄)等等,这当中还有一个通用的句柄,就是HANDLE,比如下面的语句:
HINSTANCE hInstance;
可以改成:
HANDLE hInstance;上面的2句语句都是对的。
管道的实现函数:
1) 使用A P I函数C r e a t e N a m e d P i p e,创建一个命名管道实例句柄。
2) 使用A P I函数C o n n e c t N a m e d P i p e,在命名管道实例上监听客户机连接请求。
3) 分别使用R e a d F i l e和Wr i t e F i l e这两个A P I函数,从客户机接收数据,或将数据发给客户
机。
4) 使用A P I函数D i s c o n n e c t N a m e d P i p e,关闭命名管道连接。
5) 使用A P I函数C l o s e H a n d l e,关闭命名管道实例句柄。
以下是一个实例和解析:
// Module Name: Client.cpp
//
// Purpose:
//
// This program is a simple named pipe client that demonstrates
// the API calls needed to successfully develop a basic named
// pipe client application. When this application successfully
// connects to a named pipe, the message "This is a test" is
// written to the server.
//
// There are four basic steps needed to implement a client:
//
// 1. Wait for a Named Pipe instance to become available using
// the WaitNamedPipe() API function.
// 2. Connect to the Named Pipe using the CreateFile() API
// function.
// 3. Send data to or receive data from the server using
// the WriteFile() and ReadFile() API functions.
// 4. Close the Named Pipe session using the CloseHandle() API
// functions.
//
//
// Compile:
// cl -o Client Client.cpp
//
// Command Line Options:
// None
//
#include <windows.h>
#include <stdio.h>
#define PIPE_NAME "\\\\.\\Pipe\\Jim"
void main(void) {
HANDLE PipeHandle;
DWORD BytesWritten;
if (WaitNamedPipe(PIPE_NAME, NMPWAIT_WAIT_FOREVER) == 0)
{
printf("WaitNamedPipe failed with error %d\n",
GetLastError());
return;
}
// Create the named pipe file handle
if ((PipeHandle = CreateFile(PIPE_NAME,
GENERIC_READ | GENERIC_WRITE, 0,
(LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL)) == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed with error %d\n", GetLastError());
return;
}
if (WriteFile(PipeHandle, "This is a test", 14, &BytesWritten,
NULL) == 0)
{
printf("WriteFile failed with error %d\n", GetLastError());
CloseHandle(PipeHandle);
return;
}
printf("Wrote %d bytes", BytesWritten);
CloseHandle(PipeHandle);
}
// Module Name: Server.cpp
//
// Purpose:
//
// This program is a simple named pipe server that demonstrates
// the API calls needed to successfully develop a basic named
// pipe server application. When this application receives a
// client connection, it reads the data from the pipe and
// reports the received message.
//
// You need five basic steps to write a named pipe server:
//
// 1. Create a named pipe instance handle using the
// CreateNamedPipe() API function.
// 2. Listen for a client connection on a pipe instance using
// the ConnectNamedPipe() API function.
// 3. Receive from and send data to the client using the
// ReadFile() and WriteFile() API functions.
// 4. Close down the named pipe connection using the
// DisconnectNamedPipe() API function.
// 5. Close the named pipe instance handle using the
// CloseHandle() API function.
//
// Compile:
// cl -o Server Server.cpp
//
// Command Line Options:
// None
//
#include <windows.h>
#include <stdio.h>
void main(void)
{
HANDLE PipeHandle;
DWORD BytesRead;
CHAR buffer[256];
if ((PipeHandle = CreateNamedPipe("\\\\.\\Pipe\\Jim",
PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1,
0, 0, 1000, NULL)) == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe failed with error %d\n",
GetLastError());
return;
}
printf("Server is now running\n");
if (ConnectNamedPipe(PipeHandle, NULL) == 0)
{
printf("ConnectNamedPipe failed with error %d\n",
GetLastError());
CloseHandle(PipeHandle);
return;
}
if (ReadFile(PipeHandle, buffer, sizeof(buffer),
&BytesRead, NULL) <= 0)
{
printf("ReadFile failed with error %d\n", GetLastError());
CloseHandle(PipeHandle);
return;
}
printf("%.*s\n", BytesRead, buffer);
if (DisconnectNamedPipe(PipeHandle) == 0)
{
printf("DisconnectNamedPipe failed with error %d\n",
GetLastError());
return;
}
CloseHandle(PipeHandle);
}
这两个程序没有多少可以说明的。都很简单。