现在的位置: 首页 > 综合 > 正文

命名管道

2014年02月17日 ⁄ 综合 ⁄ 共 8143字 ⁄ 字号 评论关闭

P I P E _ A C C E S S _ D U P L E X G E N E R I C _ R E A D I 双向  G E N E R I C _ W R I T E
G E N E R I C _ R E A D

P I P E _ A C C E S S _ O U T B O U N D
单向
-
> G E N E R I C _ R E A D

P I P E _ A C C E S S _ I N B O U N D <-单向 G E N E R I C _ W R I T E

-----------------------------------------------------

W R I T E _ D A C标志使我们的程序能够更
新管道的授权访问控制列表(D A C L)

例如,对于已拥有管道访问权的一名用户,假定我们现在打算拒绝他的访问,便可使
用安全A P I函数,修改管道的D A C L。

如何构建空的授权访问控制列表(NULL DACL):

Wi n 3 2安全A P I函数来进行。如果想为S E C U R I T Y _ D E S C R I P TO R结构分配一个空的
D A C L,便需采取下述操作:
1) 创建并初始化一个S E C U R I T Y _ D E S C R I P TO R结构,这是用A P I函数I n i t i a l i z e S e c u r i t y
D e s c r i p t o r来进行的。
2)  为S E C U R I T Y _ D E S C R I P TO R结构分配一个空的D A C L,这是用A P I函数
S e t S e c u r i t y D e s c r i p t o r D a c l来进行的。
成功建立一个新的 S E C U R I T Y _ D E S C R I P TO R结构后,必须将其分配给一个
S E C U R I T Y _ AT T R I B U T E S结构。到这时为止,我们便已作好了准备,可开始调用像
C r e a t e N a m e d P i p e这样的Wi n 3 2函数,同时使用新建的S E C U R I T Y _ AT T R I B U T E S结构,其中包含
了一个空的D A C L。

------------------------------------------------------------

server:

#include <windows.h>
#include <stdio.h>

int main(void)
{
	HANDLE PipeHandle;
	DWORD BytesRead;
	CHAR buffer[256];

	if ((PipeHandle = CreateNamedPipe("\\\\.\\Pipe\\Jim",
		PIPE_ACCESS_DUPLEX, //open mode
        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // 
        1,//Num. of Pipes: between 1 and PIPE_UNLIMITED_INSTANCES
	0, // buffer size
        0, // buffer size
        1000, //timeout
        NULL //Security descriptor
       )) == INVALID_HANDLE_VALUE)
	{
		printf("CreateNamedPipe failed with error %d\n",
			GetLastError());
		return 0;
	}

	printf("Server is now running\n");

	if (ConnectNamedPipe(PipeHandle, NULL) == 0)
	{
		printf("ConnectNamedPipe failed with error %d\n",
			GetLastError());
		CloseHandle(PipeHandle);
		return 0;
	}

	if (ReadFile(PipeHandle, buffer, sizeof(buffer),
		&BytesRead,  NULL) <= 0)
	{
		printf("ReadFile failed with error %d\n", GetLastError());
		CloseHandle(PipeHandle);
		return 0;
	}

	printf("%.*s\n", BytesRead, buffer);

	if (DisconnectNamedPipe(PipeHandle) == 0)
	{
		printf("DisconnectNamedPipe failed with error %d\n",
			GetLastError());
		return 0;
	}

	CloseHandle(PipeHandle);
	return 0;
}

thread server:

#include <windows.h>
#include <stdio.h>
#include <conio.h>

#define NUM_PIPES 5

DWORD WINAPI PipeInstanceProc(LPVOID lpParameter);

void main(void) 
{
	HANDLE ThreadHandle;
	INT i;
	DWORD ThreadId;

	for(i = 0; i < NUM_PIPES; i++)
	{
		// Create a thread to serve each pipe instance  
		if ((ThreadHandle = CreateThread(NULL, 0, PipeInstanceProc,
			NULL, 0, &ThreadId)) == NULL)
		{
			printf("CreateThread failed with error %\n",
				GetLastError());
			return;
		}
		CloseHandle(ThreadHandle);
	}

	printf("Press a key to stop the server\n");
	_getch();
}

//
// Function: PipeInstanceProc
//
// Description:
//     This function handles the communication details of a single
//     named pipe instance.
//     
DWORD WINAPI PipeInstanceProc(LPVOID lpParameter)
{
	HANDLE PipeHandle;
	DWORD BytesRead;
	DWORD BytesWritten;
	CHAR Buffer[256];

	if ((PipeHandle = CreateNamedPipe("\\\\.\\PIPE\\jim",
		PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
		NUM_PIPES, 0, 0, 1000, NULL)) == INVALID_HANDLE_VALUE)
	{
		printf("CreateNamedPipe failed with error %d\n",
			GetLastError());
		return 0;
	}

	// Serve client connections forever
	while(1) 
	{
		if (ConnectNamedPipe(PipeHandle, NULL) == 0)
		{
			printf("ConnectNamedPipe failed with error %d\n",
				GetLastError());
			break;
		}

		// Read data from and echo data to the client until
		// the client is ready to stop
		while(ReadFile(PipeHandle, Buffer, sizeof(Buffer),
			&BytesRead,  NULL) > 0)
		{
			printf("Echo %d bytes to client\n", BytesRead);

			if (WriteFile(PipeHandle, Buffer, BytesRead,
				&BytesWritten, NULL) == 0)
			{
				printf("WriteFile failed with error %d\n",
					GetLastError());
				break;
			}
		}

		if (DisconnectNamedPipe(PipeHandle) == 0)
		{
			printf("DisconnectNamedPipe failed with error %d\n",
				GetLastError());
			break;
		}
	}

	CloseHandle(PipeHandle);
	return 0;
}

overlapped server:

重叠式I / O:F I L E _ F L A G _ O V E R L A P P E D
重叠式I / O是一种特殊的输入/输出机制,允许Win32 API函数(如R e a d F i l e和Wr i t e F i l e)在发
出I / O请求之后,以异步方式工作。具体的工作原理是:向这些A P I函数传递一个O V E R L A P P E D
(重叠式)结构,然后使用 A P I函数G e t O v e r l a p p e d R e s u l t,从原来那个O V E R L A P P E D结构中,
取得一次I / O请求的结果。如果在使用重叠式结构的前提下,调用一个 Win32 API函数,那么
调用无论如何都会立即返回!

该应用实际是一个“反射”
或“回应”服务器,用于从客户机读取数据,并将其原封不动地打回

#include <windows.h>
#include <stdio.h>

#define NUM_PIPES 5
#define BUFFER_SIZE 256

void main(void)
{
	HANDLE PipeHandles[NUM_PIPES];
	DWORD BytesTransferred;
	CHAR Buffer[NUM_PIPES][BUFFER_SIZE];
	INT i;
	OVERLAPPED Ovlap[NUM_PIPES];
	HANDLE Event[NUM_PIPES];

	// For each pipe handle instance, the code must maintain the 
	// pipes' current state, which determines if a ReadFile or 
	// WriteFile is posted on the named pipe. This is done using
	// the DataRead variable array. By knowing each pipe's 
	// current state, the code can determine what the next I/O 
	// operation should be.
	BOOL DataRead[NUM_PIPES];

	DWORD Ret;
	DWORD Pipe;

	for(i = 0; i < NUM_PIPES; i++)
	{
		// Create a named pipe instance
		if ((PipeHandles[i] = CreateNamedPipe("\\\\.\\PIPE\\jim",
			PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
			PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, NUM_PIPES,
			0, 0, 1000, NULL)) == INVALID_HANDLE_VALUE)
		{
			printf("CreateNamedPipe for pipe %d failed "
				"with error %d\n", i, GetLastError());
			return;
		}

		// Create an event handle for each pipe instance. This
		// will be used to monitor overlapped I/O activity on 
		// each pipe.
		if ((Event[i] = CreateEvent(NULL, TRUE, FALSE, NULL)) 
			== NULL)
		{
			printf("CreateEvent for pipe %d failed with error %d\n",
				i, GetLastError());
			continue;
		}

		// Maintain a state flag for each pipe to determine when data
		// is to be read from or written to the pipe
		DataRead[i] = FALSE;

		ZeroMemory(&Ovlap[i], sizeof(OVERLAPPED));
		Ovlap[i].hEvent = Event[i];

		// Listen for client connections using ConnectNamedPipe()
		if (ConnectNamedPipe(PipeHandles[i], &Ovlap[i]) == 0)
		{
			if (GetLastError() != ERROR_IO_PENDING)
			{
				printf("ConnectNamedPipe for pipe %d failed with",
				    " error %d\n", i, GetLastError());
				CloseHandle(PipeHandles[i]);
				return;
			}
		}
	}

	printf("Server is now running\n");


	// Read and echo data back to Named Pipe clients forever
	while(1) 
	{
		if ((Ret = WaitForMultipleObjects(NUM_PIPES, Event, 
			FALSE, INFINITE)) == WAIT_FAILED)
		{
			printf("WaitForMultipleObjects failed with error %d\n",
				GetLastError());
			return;
		}

		Pipe = Ret - WAIT_OBJECT_0;

		ResetEvent(Event[Pipe]);

		// Check overlapped results, and if they fail, reestablish 
		// communication for a new client; otherwise, process read 
		// and write operations with the client

		if (GetOverlappedResult(PipeHandles[Pipe], &Ovlap[Pipe],
			&BytesTransferred, TRUE) == 0)
		{
			printf("GetOverlapped result failed %d start over\n", 
				GetLastError());

			if (DisconnectNamedPipe(PipeHandles[Pipe]) == 0)
			{
				printf("DisconnectNamedPipe failed with error %d\n",
					GetLastError());
				return;
			}

			if (ConnectNamedPipe(PipeHandles[Pipe],
				&Ovlap[Pipe]) == 0)
			{
				if (GetLastError() != ERROR_IO_PENDING)
				{
					// Severe error on pipe. Close this
					// handle forever.
					printf("ConnectNamedPipe for pipe %d failed with"
						"error %d\n", i, GetLastError());
					CloseHandle(PipeHandles[Pipe]);
				}
			}

			DataRead[Pipe] = FALSE;
		} 
		else
		{
			// Check the state of the pipe. If DataRead equals 
			// FALSE, post a read on the pipe for incoming data.
			// If DataRead equals TRUE, then prepare to echo data 
			// back to the client.

			if (DataRead[Pipe] == FALSE)
			{
				// Prepare to read data from a client by posting a
				// ReadFile operation

				ZeroMemory(&Ovlap[Pipe], sizeof(OVERLAPPED));
				Ovlap[Pipe].hEvent = Event[Pipe];

				if (ReadFile(PipeHandles[Pipe], Buffer[Pipe],
					BUFFER_SIZE, NULL, &Ovlap[Pipe]) == 0)
				{
					if (GetLastError() != ERROR_IO_PENDING)
					{
						printf("ReadFile failed with error %d\n",
						GetLastError());
					}
				}

				DataRead[Pipe] = TRUE;
			}
			else
			{
				// Write received data back to the client by
				// posting a WriteFile operation.
				printf("Received %d bytes, echo bytes back\n",
					BytesTransferred);

				ZeroMemory(&Ovlap[Pipe], sizeof(OVERLAPPED));
				Ovlap[Pipe].hEvent = Event[Pipe];

				if (WriteFile(PipeHandles[Pipe], Buffer[Pipe],
					BytesTransferred, NULL, &Ovlap[Pipe]) == 0)
				{
					if (GetLastError() != ERROR_IO_PENDING)
					{
						printf("WriteFile failed with error %d\n",
						GetLastError());
					}
				}

				DataRead[Pipe] = FALSE;
			}
		}
	}		
}

--------------------------------------------------------

client:

#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);
}

其他API

C a l l N a m e d P i p e

在一次调用中,同时执行读和写操作。其中, C a l l N a m e d P i p e函数允许客户机应用建立与一个
消息类型的管道的连接(假如当时没有可用的管道实例,便会一直等候下去) ,然后在管道上
读写数据,最后关闭这个管道。事实上,这几乎是一个完整的客户机应用,只是已在一个调
用中全部写好了!

Tr a n s a c t N a m e d P i p e

函数既可在客户机应用中使用,亦可在服务器应用中使用。设计它的
目的是为了将读操作与写操作整合到一个 A P I调用之中。

G e t N a m e d P i p e H a n d l e S t a t e,S e t N a m e d P i p e H a n d l e S t a t e

获得或者设定: 运行模式(消息或字节模式) 、管道实例数以及缓冲区信息等等

G e t N a m e d P i p e I n f o这个A P I函数用于获得缓冲区大小以及管道实例最大数量信息

P e e k N a m e d P i p e,可用它对命令管道内的数据进行浏览,同时毋需将
其从管道的内部缓冲区挪出。

假如应用程序希望对进入的数据进行“轮询” ,以免进行R e a d F i l e这个A P I调用时发生“锁定”现象(执行暂停) ,便可考虑使用这一函数。

另外,假若应用程序需要在数据实际接收之前,先作一番检查,这个函数也是相当有用的。例如,应
用程序可能希望根据进入消息的长度,先对应用程序的缓冲区进行一番调节。 

抱歉!评论已关闭.