1、最简单的例子:
服务端:
#include
#include
void main(void)
{
HANDLE PipeHandle;
DWORD BytesRead;
CHAR buffer[256] = {0};
if ((PipeHandle = CreateNamedPipe("\\\\.\\Pipe\\mypipe",PIPE_ACCESS_DUPLEX,PIPE_TYPE_BYTE|PIPE_READMODE_BYTE,1,0,0,1000,NULL)) == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe failed with error %x \n",GetLastError());
return;
}
printf("Server is now running \n");
if (ConnectNamedPipe(PipeHandle,NULL) == 0)
{
printf("ConnectNamePipe failed with error %x \n",GetLastError());
CloseHandle(PipeHandle);
return;
}
if(ReadFile(PipeHandle,buffer,sizeof(buffer),&BytesRead,NULL) <= 0)
{
printf("ReadFile failed with error %x \n",GetLastError());
CloseHandle(PipeHandle);
return;
}
printf("byteread = %d,buffer = %s \n",BytesRead,buffer);
if (DisconnectNamedPipe(PipeHandle) == 0)
{
printf("DisconnectNamedPipe failed with error %x \n",GetLastError());
return;
}
CloseHandle(PipeHandle);
system("pause");
}
注意:同步情况下,ReadFile是阻塞读,遇到下列一个情况返回:
(1)A write operation completes on the write end of the pipe.
(2)The number of bytes requested is read.
(3)An error occurs.
客户端:
#include
#include
void main(void)
{
HANDLE PipeHandle;
DWORD BytesWritten;
if (WaitNamedPipe("\\\\.\\Pipe\\mypipe", NMPWAIT_WAIT_FOREVER) == 0)
{
printf("CreateNamedPipe failed with error %x \n",GetLastError());
return;
}
if ((PipeHandle = CreateFile("\\\\.\\Pipe\\mypipe",GENERIC_READ | GENERIC_WRITE, 0 ,(LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed with error %x \n",GetLastError());
return;
}
if(WriteFile(PipeHandle,"This is a test", 14, &BytesWritten, NULL) == 0)
{
printf("WriteFile failed with error %x \n",GetLastError());
CloseHandle(PipeHandle);
return;
}
printf("Wrote %d bytes \n", BytesWritten);
CloseHandle(PipeHandle);
system("pause");
}
2、多线程设计
服务端:为每一个实例创建一个单独线程进程通信
#include
#include
#include "CC_Debug.h"
#define NUM_PIPES 2
DWORD WINAPI PipeInstanceProc(LPVOID lpParameter);
void main(void)
{
HANDLE ThreadHandle;
INT i;
DWORD ThreadId;
for(i = 0; i < NUM_PIPES; i++)
{
//为每一个实例创建一个线程
ThreadHandle = CreateThread(NULL,0,PipeInstanceProc,NULL,0,&ThreadId);
if (NULL == ThreadHandle)
{
CC_A_INFO("CreateThread failed with error %x \n",GetLastError());
return;
}
else
{
CC_A_INFO("CreateThread success! ThreadHandle = %x",ThreadHandle);
}
CloseHandle(ThreadHandle);
}
system("pause");
}
DWORD WINAPI PipeInstanceProc(LPVOID lpParameter)
{
HANDLE PipeHandle;
DWORD BytesRead;
DWORD BytesWritten;
CHAR Buffer[256];
//注意:这里一定要更改管道实例的参数,否则不能创建管道。
if ((PipeHandle = CreateNamedPipe("\\\\.\\Pipe\\mypipe",PIPE_ACCESS_DUPLEX,PIPE_TYPE_BYTE|PIPE_READMODE_BYTE,NUM_PIPES,0,0,1000,NULL)) == INVALID_HANDLE_VALUE)
{
CC_A_INFO("CreateNamedPipe failed with error %x \n",GetLastError());
return 0;
}
else
{
CC_A_INFO("CreateNamedPipe sucess! PipeHandle = %x",PipeHandle);
}
CC_A_INFO("Server is now running ......");
while (1)
{
if (ConnectNamedPipe(PipeHandle,NULL) == 0)
{
CC_A_INFO("ConnectNamedPipe failed!");
break;
}
else
{
CC_A_INFO("ConnectNamedPipe success!");
}
while (ReadFile(PipeHandle,Buffer,sizeof(Buffer),&BytesRead,NULL) > 0)
{
CC_A_INFO("Echo %d bytes to Client",BytesRead);
}
//这里要断开与客户的连接,如果调用ConnectNamedPipe,可以为另外一个客户的提供服务。
if (DisconnectNamedPipe(PipeHandle) == 0)
{
printf("DisconnectNamedPipe failed with error %x \n",GetLastError());
CC_A_INFO("Server DisconnectNamedPipe");
return 1;
}
}
CC_A_INFO("Server exit");
CloseHandle(PipeHandle);
system("pause");
}
客户端:
#include
#include
#include "CC_Debug.h"
void main(void)
{
HANDLE PipeHandle;
DWORD BytesWritten = 0;
if (WaitNamedPipe("\\\\.\\Pipe\\mypipe", NMPWAIT_WAIT_FOREVER) == 0)
{
printf("CreateNamedPipe failed with error %x \n",GetLastError());
return;
}
if ((PipeHandle = CreateFile("\\\\.\\Pipe\\mypipe",GENERIC_READ | GENERIC_WRITE, 0 ,(LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) == INVALID_HANDLE_VALUE)
{
CC_A_INFO("CreateFile failed with error %x \n",GetLastError());
return;
}
if(WriteFile(PipeHandle,"This is a test", 14, &BytesWritten, NULL) == 0)
{
CC_A_INFO("WriteFile failed with error %x \n",GetLastError());
CloseHandle(PipeHandle);
return;
}
CC_A_INFO("Wrote %d bytes \n", BytesWritten);
CloseHandle(PipeHandle);
system("pause");
}
3、重叠IO实现
服务端:
#include
#include
#include "CC_Debug.h"
#define NUM_PIPES (2)
#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];
BOOL DataRead[NUM_PIPES]; //用于保存pipe的状态
DWORD Ret;
DWORD Pipe;
for(i = 0; i < NUM_PIPES; i++)
{
//注意:这里一定要更改管道实例的参数,否则不能创建管道。同时要指定FILE_FLAG_OVERLAPPED。
if ((PipeHandles[i] = CreateNamedPipe("\\\\.\\Pipe\\mypipe",PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE,NUM_PIPES,0,0,1000,NULL)) == INVALID_HANDLE_VALUE)
{
CC_A_INFO("CreateNamedPipe failed with error %x \n",GetLastError());
return;
}
else
{
CC_A_INFO("CreateNamedPipe sucess! PipeHandle = %x",PipeHandles[i]);
}
Event[i] = CreateEvent(NULL,TRUE,FALSE,NULL); //手动重置、初始为无信号。
if (NULL == Event[i])
{
CC_A_INFO("CreateEvent failed error = %x",GetLastError());
continue;
}
DataRead[i] = FALSE;
ZeroMemory(&Ovlap[i],sizeof(OVERLAPPED));
Ovlap[i].hEvent = Event[i];
/*
ConnectNamedPipe:等待客户端连接
&Ovlap[i]:如果此参数为NULL,如果此参数设为NULL,表示将线程挂起,直到一个客户同管道连接为时返回。
如果传入OVERLAPPED,表示是异步的,函数立即返回;
此时,如管道尚未连接,客户端同管道连接时就会触发lpOverlapped结构中的事件对象。
随后,可用一个等待函数来监视连接。
*/
if (ConnectNamedPipe(PipeHandles[i],&Ovlap[i]) == 0) //这里要传入一个Overlap结构。
{
if (GetLastError() != ERROR_IO_PENDING) //ERROR_IO_PENDING说明重叠I/O投递成功,只是没有处理完成。
{
CC_A_INFO("ConnectNamedPipe failed ,errorcode = %x",GetLastError());
CloseHandle(PipeHandles[i]);
return;
}
}
}
CC_A_INFO("Server is now running ....");
while(1)
{
/*
WaitForMultipleObjects主要参数说明:
(1)NUM_PIPES,等待事件个数
(2)Event,事件数组。
(3)FALSE:此参数如果为TRUE,则需要等所有对象都有信号,才返回。为FALSE,则只要有一个有信号,就返回
其返回值减去WAIT_OBJECT_0 就是参数lpHandles数组的序号。如果同时有多个内核对象被触发,这
个函数返回的只是其中序号最小的那个。
(4)INFINITE:等待时间。
*/
Ret = WaitForMultipleObjects(NUM_PIPES,Event,FALSE,INFINITE); //这里每个客户端连接上的时候,都会设置有信号。
if (Ret == WAIT_FAILED)
{
CC_A_INFO("WaitForMultipleObjects failed with error = %x",GetLastError());
return;
}
Pipe = Ret - WAIT_OBJECT_0;
ResetEvent(Event[Pipe]); //设置成无信号
/*
GetOverlappedResult:判断异步操作是否完成,通过OVERLAPPED结构中的hEvent是否被置位来判断。非0表示成功,0表示失败。
(1)PipeHandles[Pipe]:管道句柄
(2)&Ovlap[Pipe]:需要检查的结构
(3)BytesTransferred:用于容纳传输字节数量的一个变量
(4)如果为TRUE,就一直等到异步操作结束才返回。FALSE表示立即返回。
*/
if (GetOverlappedResult(PipeHandles[Pipe],&Ovlap[Pipe],&BytesTransferred,TRUE) == 0)
{
CC_A_INFO("GetOverlappedResult failed erro = %x",GetLastError());
if (DisconnectNamedPipe(PipeHandles[Pipe]) == 0)
{
CC_A_INFO("DisconnectNamePipe failed with error = %x",GetLastError());
return;
}
{
CC_A_INFO("DisconnectNamedPipe,wait another client!");
}
if (ConnectNamedPipe(PipeHandles[Pipe],&Ovlap[Pipe]) == 0)
{
if (GetLastError() != ERROR_IO_PENDING)
{
CC_A_INFO("ConnectNamedPipe failed,error = %x",GetLastError());
CloseHandle(PipeHandles[Pipe]);
}
}
DataRead[Pipe] = FALSE;
}
else
{
CC_A_INFO("GetOverlappedResult success! BytesTransferred = %d",BytesTransferred);
if (DataRead[Pipe] == FALSE)
{
ZeroMemory(&Ovlap[i],sizeof(OVERLAPPED));
Ovlap[i].hEvent = Event[i];
//这里不会阻塞,而是会以异步方式继续工作。BUFFER_SIZE为要读的长度。
//问题:我客户端只写了14个字节,而这儿要读BUFFER_SIZE长度,那为什么这个也会返回呢?难道是按实际读取的长度算?
if (ReadFile(PipeHandles[Pipe],Buffer[Pipe],BUFFER_SIZE,NULL,&Ovlap[Pipe]) == 0)
{
if (GetLastError() != ERROR_IO_PENDING)
{
CC_A_INFO("ReadFile failed,error = %x",GetLastError());
}
}
else
{
CC_A_INFO("ReadFile return");
}
DataRead[Pipe] = TRUE;
}
else
{
CC_A_INFO("Received %d bytes, echo bytes back", BytesTransferred);
ZeroMemory(&Ovlap[Pipe],sizeof(OVERLAPPED));
Ovlap[Pipe].hEvent = Event[Pipe]; //这里会不会将刚刚读成功的信号,给覆盖了???
//问题1、如果使劲写,客户端不读,会怎么样?
//问题2、WriteFile完成后,GetOverlappedResult会不会设置有信号?—— 也会的!!!
//问题3、同时读和写,如果返回有信号了,我知道是读成功了,还是写成功了啊???不知道为啥啊?
if(WriteFile(PipeHandles[Pipe],"This is a haha66", 16, NULL, &Ovlap[Pipe]) == 0)
{
if (GetLastError() != ERROR_IO_PENDING)
{
CC_A_INFO("WriteFile failed,error = %x",GetLastError());
}
}
DataRead[Pipe] = FALSE;
}
}
}
system("pause");
}
#include
#include
#include "CC_Debug.h"
void main(void)
{
HANDLE PipeHandle;
DWORD BytesWritten = 0;
DWORD BytesRead;
CHAR Buffer[256];
//等待管道实例有效,如果在超时值变为零以前,有一个管道可以使用,则 WaitNamedPipe 将返回 True,
//如果指定的命名管道没有实例存在,即没有服务端创建该命名管道,函数无视超时等待时间直接返回0
if (WaitNamedPipe("\\\\.\\Pipe\\mypipe", NMPWAIT_WAIT_FOREVER) == 0)
{
CC_A_INFO("CreateNamedPipe failed with error %x \n",GetLastError());
return;
}
if ((PipeHandle = CreateFile("\\\\.\\Pipe\\mypipe",GENERIC_READ | GENERIC_WRITE, 0 ,(LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) == INVALID_HANDLE_VALUE)
{
CC_A_INFO("CreateFile failed with error %x \n",GetLastError());
return;
}
if(WriteFile(PipeHandle,"This is a test", 14, &BytesWritten, NULL) == 0)
{
CC_A_INFO("WriteFile failed with error %x \n",GetLastError());
CloseHandle(PipeHandle);
return;
}
CC_A_INFO("Wrote %d bytes \n", BytesWritten);
if (ReadFile(PipeHandle,Buffer,sizeof(Buffer),&BytesRead,NULL) == 0)
{
CC_A_INFO("Echo %d bytes to Client",BytesRead);
}
else
{
CC_A_INFO("Client Read %d bytes from server",BytesRead);
}
CloseHandle(PipeHandle);
system("pause");
}