windows 管道通信 C++
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1849918/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pipe communication C++
提问by Ricardo Acras
I′m writing two litle c++ apps that must communicate. First one will be a service which, every once in a while, must alert the user for something. Since a service cannot create windows I designed the app to be two separate executables.
我正在编写两个必须进行通信的小 C++ 应用程序。第一个将是一项服务,每隔一段时间,必须提醒用户某些事情。由于服务无法创建窗口,我将应用程序设计为两个独立的可执行文件。
The service will use a notifier to communicate.
该服务将使用通知程序进行通信。
The service needs only to send text messages to the notifier wich will show up a balloon at system tray.
该服务只需要向通知程序发送文本消息,通知程序就会在系统托盘上显示一个气球。
I′m trying to use named pipes and I think I′m almost there, but not quite there. What I have so far is:
我正在尝试使用命名管道,我想我快到了,但还没有完全到位。到目前为止我所拥有的是:
At the notifier side:
在通知方:
m_hInPipe = CreateNamedPipe(L"\\.\pipe\nhsupspipe", PIPE_ACCESS_INBOUND,
PIPE_WAIT, 1, 1024, 1024, 60, NULL);
Meaning I created a pipe named nhsupspipe, an inbound pipe.
这意味着我创建了一个名为 nhsupspipe 的管道,一个入站管道。
At the service side:
在服务端:
if (!WriteFile(m_hOutPipe, "My message to the user?", 23, &escritos, &o))
std::cout << "ERROR: " << GetLastError();
Debugging I can see that it is all ok, the pipe is created and the WriteFile writes my 23 bytes to the pipe.
调试我可以看到一切正常,管道已创建,WriteFile 将我的 23 个字节写入管道。
My question is: How, in the notifier side I′ll be able to read these bytes? Is there any message sent to the process? Do I have to write a handler for the pipe? Anything?
我的问题是:如何在通知端读取这些字节?是否有任何消息发送到进程?我是否必须为管道编写处理程序?任何事物?
回答by Eugen Constantin Dinca
Some simple snippets from the client (your service) & the server (the notifier) [Note: This is adapted from a project I've done a while ago which in turn was heavily "influenced" by the MSDN samples from CreateNamedPipe & co]:
来自客户端(您的服务)和服务器(通知程序)的一些简单片段 [注意:这是改编自我不久前完成的一个项目,而该项目又受到来自 CreateNamedPipe & co 的 MSDN 示例的严重“影响”] :
Server side:
服务器端:
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;
The client:
客户端:
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;
The Messagementioned above is a structure that will be your message, which you will probably want to pack.
上面提到的Message是一个结构,它将成为您的消息,您可能想要打包。
Since in your scenario the client (the service) will probably be up & running before the server (the notifier) you'll need to have in place some kind of reconnection strategy on the client side.
由于在您的场景中,客户端(服务)可能会在服务器(通知程序)之前启动并运行,因此您需要在客户端实施某种重新连接策略。
And on a slightly different note you should consider carefully what Mr. Osterman said in his reply(even for nothing else but because he's Larry Osterman).
换个角度来说,你应该仔细考虑奥斯特曼先生在他的回复中所说的话(即使没有别的,只是因为他是拉里奥斯特曼)。
回答by Ryan
You need to use ReadFileor ReadFileEx(for Overlapped I/O) on notifier side typically in a thread or message loop. Also look at the documentation for CreateNamedPipeand WaitNamedPipe.
通常在线程或消息循环中,您需要在通知程序端使用ReadFile或ReadFileEx(用于重叠 I/O)。另请查看CreateNamedPipe和WaitNamedPipe的文档。
回答by ReinstateMonica Larry Osterman
In this circumstance, I'd probably use RPC instead of raw named pipes. With raw named pipes, you have to parse the data from the client which introduces the possibility of security bugs. With RPC you can let RPC parse the data for you which decreases the chance of introducing an error.
在这种情况下,我可能会使用 RPC 而不是原始命名管道。使用原始命名管道,您必须解析来自客户端的数据,这会引入安全漏洞的可能性。使用 RPC,您可以让 RPC 为您解析数据,从而减少引入错误的机会。
回答by kenny
Not exactly the question, but another option is CreateEvent() and a memory mapped file.
不完全是问题,但另一个选项是 CreateEvent() 和内存映射文件。
回答by Jerry Coffin
If I were doing this, I'd have the service side do the CreateNamedPipe
(outbound), and then call ConnectNamedPipe
to wait for the notifier to connect.
如果我这样做,我会让服务端做CreateNamedPipe
(出站),然后调用ConnectNamedPipe
等待通知程序连接。
On the notifier side, I'd use CreateFile
with FILE_FLAG_OVERLAPPED
. With that, the handle to the pipe will be signaled when data becomes available to read. Your notifier will (presumably) also be maintaining a GUI, so you'll probably want to have it call MsgWaitForMultipleObjects
in its event loop. That will wait for messages to be processed ordata coming in on the pipe to be processed. That will work almost like a normal event loop, except that its return value is slightly different from GetMessage()
-- it'll return WAIT_OBJECT_0
if your handle is signaled, or WAIT_OBJECT_0 + 1
if you have a message (assuming you only have it wait on the one handle -- it's really WAIT_OBJECT_0 + N
, where N
is the number of handles you had it wait on). For the most part, it's like a normal PeekMessage
or GetMessage
loop -- wait 'til there's something to do, do it, wait again.
在通知程序方面,我会使用CreateFile
with FILE_FLAG_OVERLAPPED
。这样,当数据可供读取时,管道的句柄将收到信号。您的通知程序(大概)也将维护一个 GUI,因此您可能希望MsgWaitForMultipleObjects
在其事件循环中调用它。这将等待要处理的消息或要处理的管道上的数据。这将几乎像一个普通的事件循环一样工作,除了它的返回值与GetMessage()
-WAIT_OBJECT_0
如果您的句柄有信号,或者WAIT_OBJECT_0 + 1
如果您有消息(假设您只让它在一个句柄上等待),它会返回-真的WAIT_OBJECT_0 + N
,N
您等待的句柄数量在哪里)。在大多数情况下,它就像一个正常的PeekMessage
或GetMessage
循环——等到有事可做,去做,再等。