//Server/Pipe/[Path]Name |
其中,第一部分//Server指定了服务器的名字,命名管道服务即在此服务器创建,其字串部分可表示为一个小数点(表示本机)、星号(当前网络字段)、域名或是一个真正的服务;第二部分/Pipe与邮槽的/Mailslot一样是一个不可变化的硬编码字串,以指出该文件是从属于NPFS;第三部分/[Path]Name则使应用程序可以唯一定义及标识一个命名管道的名字,而且可以设置多级目录。
命名管道提供了两种基本的通信模式:字节模式和消息模式。可在CreateNamePipe()创建命名管道时分别用PIPE_TYPE_BYTE和PIPE_TYPE_MESSAGE标志进行设定。在字节模式中,信息以连续字节流的形式在客户与服务器之间流动。这也就意味着,对于客户机应用和服务器应用,在任何一个特定的时间段内,都无法准确知道有多少字节从管道中读出或写入。在这种通信模式中,一方在向管道写入某个数量的字节后,并不能保证管道另一方能读出等量的字节。对于消息模式,客户机和服务器则是通过一系列不连续的数据包进行数据的收发。从管道发出的每一条消息都必须作为一条完整的消息读入。
使用命名管道
管道服务器首次调用CreateNamedPipe()函数时,使用nMaxInstance参数指定了能同时存在的管道实例的最大数目。服务器可以重复调用CreateNamedPipe()函数去创建管道新的实例,直至达到设定的最大实例数。下面给出CreateNamedPipe()的函数原型:
HANDLE CreateNamedPipe( LPCTSTR lpName, // 指向管道名称的指针 DWORD dwOpenMode, // 管道打开模式 DWORD dwPipeMode, // 管道模式 DWORD nMaxInstances, // 最大实例数 DWORD nOutBufferSize, // 输出缓存大小 DWORD nInBufferSize, // 输入缓存大小 DWORD nDefaultTimeOut, // 超时设置 LPSECURITY_ATTRIBUTES lpSecurityAttributes // 安全属性指针 ); |
m_hPipe = CreateNamedPipe("////.//Pipe//Test", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, 0, 0, 1000, NULL); // 创建命名管道 if (m_hPipe == INVALID_HANDLE_VALUE) m_sMessage = "创建命名管道失败!"; else{ m_sMessage = "成功创建命名管道!"; AfxBeginThread(ReadProc, this); // 开启线程 } |
UINT ReadProc(LPVOID lpVoid) { char buffer[1024]; // 数据缓存 DWORD ReadNum; CServerView* pView = (CServerView*)lpVoid; // 获取视句柄 if (ConnectNamedPipe(pView->m_hPipe, NULL) == FALSE) // 等待客户机的连接 { CloseHandle(pView->m_hPipe); // 关闭管道句柄 pView->m_sMessage = "与客户机建立连接失败!"; // 显示信息 pView->Invalidate(); return 0; }else{ pView->m_sMessage = "与客户机建立连接!"; // 显示信息 pView->Invalidate(); } // 从管道读取数据 if (ReadFile(pView->m_hPipe, buffer, sizeof(buffer), &ReadNum, NULL) == FALSE) { CloseHandle(pView->m_hPipe); // 关闭管道句柄 pView->m_sMessage = "从管道读取数据失败!"; // 显示信息 pView->Invalidate(); } else { buffer[ReadNum] = '/0'; // 显示接收到的信息 pView->m_sMessage = CString(buffer); pView->Invalidate(); } return 1; } |
if (DisconnectNamedPipe(m_hPipe) == FALSE) // 终止连接 m_sMessage = "终止连接失败!"; else { CloseHandle(m_hPipe); // 关闭管道句柄 m_sMessage = "成功终止连接!"; } |
CString Message = "[测试数据,由客户机发出]"; // 要发送的数据 DWORD WriteNum; // 发送的是数据长度 // 等待与服务器的连接 if (WaitNamedPipe("////.//Pipe//Test", NMPWAIT_WAIT_FOREVER) == FALSE) { m_sMessage = "等待连接失败!"; // 显示信息 Invalidate(); return; } // 打开已创建的管道句柄 HANDLE hPipe = CreateFile("////.//Pipe//Test", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hPipe == INVALID_HANDLE_VALUE) { m_sMessage = "管道打开失败!"; // 显示信息 Invalidate(); return; } else { m_sMessage = "成功打开管道!"; // 显示信息 Invalidate(); } // 向管道写入数据 if (WriteFile(hPipe, Message, Message.GetLength(), &WriteNum, NULL) == FALSE) { m_sMessage = "数据写入管道失败!"; // 显示信息 Invalidate(); } else { m_sMessage = "数据成功写入管道!"; // 显示信息 Invalidate(); } CloseHandle(hPipe); // 关闭管道句柄 |