管道通信 C++
Posted
技术标签:
【中文标题】管道通信 C++【英文标题】:Pipe communication C++ 【发布时间】:2009-12-04 21:57:42 【问题描述】:我正在编写两个必须通信的小 C++ 应用程序。第一个将是一项服务,每隔一段时间,它必须提醒用户一些事情。由于服务无法创建窗口,因此我将应用设计为两个独立的可执行文件。
服务将使用通知器进行通信。
该服务只需要向通知器发送文本消息,它将在系统托盘上显示一个气球。
我正在尝试使用命名管道,我想我快到了,但还不完全到那里。到目前为止我所拥有的是:
在通知方:
m_hInPipe = CreateNamedPipe(L"\\\\.\\pipe\\nhsupspipe", PIPE_ACCESS_INBOUND,
PIPE_WAIT, 1, 1024, 1024, 60, NULL);
意思是我创建了一个名为 nhsupspipe 的管道,一个入站管道。
在服务端:
if (!WriteFile(m_hOutPipe, "My message to the user?", 23, &escritos, &o))
std::cout << "ERROR: " << GetLastError();
调试我可以看到一切正常,管道已创建,WriteFile 将我的 23 个字节写入管道。
我的问题是:如何在通知方读取这些字节?是否有任何消息发送到进程?我必须为管道编写处理程序吗?有什么事吗?
【问题讨论】:
【参考方案1】:来自客户端(您的服务)和服务器(通知程序)的一些简单的 sn-ps [注意:这是改编自我不久前完成的一个项目,而该项目又受到来自 CreateNamedPipe & co 的 MSDN 示例的严重“影响”]:
服务器端:
HANDLE hPipe = INVALID_HANDLE_VALUE;
bool bConnected = false;
hPipe = CreateNamedPipe( L"\\\\.\\pipe\\nhsupspipe",
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
sizeof( Message ),
0,
0,
NULL );
// failed to create pipe?
if( hPipe == INVALID_HANDLE_VALUE )
return -1;
// Wait for the client to connect; if it succeeds,
// the function returns a nonzero value. If the function
// returns zero, GetLastError returns ERROR_PIPE_CONNECTED.
bConnected = ConnectNamedPipe( hPipe, NULL ) ? true : ( GetLastError() == ERROR_PIPE_CONNECTED );
if( bConnected )
while( true )
unsigned long ulBytesRead = 0;
// read client requests from the pipe.
bool bReadOk = ReadFile( hPipe,
&message,
sizeof( message ),
&ulBytesRead,
NULL );
// bail if read failed [error or client closed connection]
if( !bReadOk || ulBytesRead == 0 )
break;
// all ok, process the message received
else
// the client could not connect, so close the pipe.
CloseHandle( hPipe );
return 0;
客户:
HANDLE hPipe = INVALID_HANDLE_VALUE;
// create the named pipe handle
hPipe = CreateFile( L"\\\\.\\pipe\\nhsupspipe",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL );
// if everything ok set mode to message mode
if( INVALID_HANDLE_VALUE != hPipe )
DWORD dwMode = PIPE_READMODE_MESSAGE;
// if this fails bail out
if( !SetNamedPipeHandleState( hPipe, &dwMode, NULL, NULL ) )
CloseHandle( hPipe );
return -1;
unsigned long ulBytesWritten = 0;
bool bWriteOk = WriteFile( hPipe,
( LPCVOID )&message,
sizeof( Message ),
&ulBytesWritten,
NULL );
// check if the writing was ok
if( !bWriteOk || ulBytesWritten < sizeof( Message ) )
return -1;
// written ok
return 0;
上面提到的Message是一个结构,它将成为您的消息,您可能想要pack。
由于在您的场景中,客户端(服务)可能会在服务器(通知程序)之前启动并运行,因此您需要在客户端制定某种重新连接策略。
另外,你应该仔细考虑奥斯特曼先生在他的reply 中所说的话(即使没有别的,因为他是拉里奥斯特曼)。
【讨论】:
你能告诉我如何在 VS (C++) 的单个项目中实现服务器和客户端吗? @k_programmer 如果你希望两者都在同一个进程中,你要么必须为服务器和客户端使用单独的线程,要么使用 ReadFileEx 和 WriteFileEx。尝试实施解决方案,如果您有问题,请在此处提问。 感谢您的回复。我想出了一种在同一个线程中实现服务器和客户端的方法。看起来很奇怪,但我以某种方式做到了,现在它工作正常:) @k_programmer 对于半双工协议,您不需要单独的线程。不管怎样,很高兴知道你已经弄明白了。【参考方案2】:通常在线程或消息循环中,您需要在通知程序端使用 ReadFile 或 ReadFileEx(用于重叠 I/O)。另请查看CreateNamedPipe 和WaitNamedPipe 的文档。
【讨论】:
【参考方案3】:在这种情况下,我可能会使用 RPC 而不是原始命名管道。使用原始命名管道,您必须解析来自客户端的数据,这会引入安全漏洞的可能性。使用 RPC,您可以让 RPC 为您解析数据,从而减少引入错误的机会。
【讨论】:
【参考方案4】:不完全是问题,但另一个选项是 CreateEvent() 和内存映射文件。
【讨论】:
【参考方案5】:如果我这样做,我会让服务端执行CreateNamedPipe
(出站),然后调用ConnectNamedPipe
等待通知器连接。
在通知者方面,我会使用 CreateFile
和 FILE_FLAG_OVERLAPPED
。这样,当数据可供读取时,将发出管道句柄的信号。您的通知程序(可能)也将维护一个 GUI,因此您可能希望它在其事件循环中调用 MsgWaitForMultipleObjects
。这将等待消息被处理或进入管道的数据被处理。这几乎就像一个正常的事件循环一样工作,除了它的返回值与GetMessage()
略有不同——如果你的句柄被发出信号,它将返回WAIT_OBJECT_0
,或者如果你有一条消息,它将返回WAIT_OBJECT_0 + 1
(假设你只让它在一个句柄上等待——它实际上是WAIT_OBJECT_0 + N
,其中N
是你让它等待的句柄数)。在大多数情况下,它就像一个普通的 PeekMessage
或 GetMessage
循环——等到有事要做,做,再等。
【讨论】:
以上是关于管道通信 C++的主要内容,如果未能解决你的问题,请参考以下文章