我正在编写两个必须通信的litle 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个字节写入管道。
我的问题是:在通知器方面我将如何读取这些字节?是否有任何消息发送到该流程?我是否必须为管道编写处理程序?什么?
答案 0 :(得分:5)
来自客户端(您的服务)的一些简单片段&amp;服务器(通知者) [注意:这是根据我之前做过的一个项目改编的,而这个项目又受到CreateNamedPipe&amp;的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;
上面提到的消息是一个结构,它将是您的消息,您可能希望pack。
因为在您的场景中,客户端(服务)可能会启动并且在服务器(通知程序)之前运行,您需要在客户端使用某种重新连接策略。
稍微不同的是,你应该仔细考虑奥斯特曼先生在reply中所说的话(即使只是因为他是拉里奥斯特曼)。
答案 1 :(得分:4)
您需要在通知程序端使用ReadFile或ReadFileEx(对于重叠I / O),通常在线程或消息循环中。另请参阅CreateNamedPipe和WaitNamedPipe的文档。
答案 2 :(得分:1)
在这种情况下,我可能会使用RPC而不是原始命名管道。使用原始命名管道,您必须解析来自客户端的数据,这会引入安全漏洞的可能性。使用RPC,您可以让RPC为您解析数据,从而减少引入错误的可能性。
答案 3 :(得分:0)
不完全是问题,但另一个选项是CreateEvent()和内存映射文件。
答案 4 :(得分:0)
如果我这样做,我会让服务端执行CreateNamedPipe
(出站),然后调用ConnectNamedPipe
等待通知程序连接。
在通知程序方面,我将CreateFile
与FILE_FLAG_OVERLAPPED
一起使用。这样,当数据可供读取时,将发出管道句柄的信号。您的通知程序(可能)也会维护GUI,因此您可能希望在其事件循环中调用MsgWaitForMultipleObjects
。这将等待处理要处理的管道上的消息或。这几乎就像一个普通的事件循环,除了它的返回值与GetMessage()
略有不同 - 如果你的句柄发出信号,它会返回WAIT_OBJECT_0
,如果你有信号,它会返回WAIT_OBJECT_0 + 1
一条消息(假设你只让它在一个句柄上等待 - 它真的是WAIT_OBJECT_0 + N
,其中N
是你等待的句柄数)。在大多数情况下,它就像一个普通的PeekMessage
或GetMessage
循环 - 等待直到有事做,做,再等一等。