这是第一个应用程序中的“PipeServer”:
// Open Pipe and wait until ControlProgram is connecting
Pipe.Out = INVALID_HANDLE_VALUE;
const wchar_t *data = L"*** Hello Pipe World ***";
DWORD numBytesWritten = 0;
DWORD timerinit = GetTickCount();;
while (1)
{
DWORD timer = GetTickCount();
if ((timer - timerinit) > 1000)
{
timerinit = timer;
if (ConnectNamedPipe(Pipe.Out, NULL))
{
WriteFile(
Pipe.Out, // handle to our outbound pipe
data, // data to send
wcslen(data) * sizeof(wchar_t), // length of data to send (bytes)
&numBytesWritten, // will store actual amount of data sent
NULL // not using overlapped IO
);
}
else
{
CloseHandle(Pipe.Out);
Pipe.Out = INVALID_HANDLE_VALUE;
do
{
Pipe.Out = CreateNamedPipeW(
L"\\\\.\\pipe\\mypipe", // name of the pipe
PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
PIPE_TYPE_BYTE, // send data as a byte stream
1, // only allow 1 instance of this pipe
0, // no outbound buffer
0, // no inbound buffer
0, // use default wait time
NULL // use default security attributes
);
}
while (Pipe.Out == INVALID_HANDLE_VALUE);
}
}
}
这是“PipeClient”应用程序:
///// CLIENT PROGRAM /////
#include <iostream>
#include <windows.h>
using namespace std;
int main(int argc, const char **argv)
{
wcout << "Connecting to pipe..." << endl;
// Open the named pipe
// Most of these parameters aren't very relevant for pipes.
HANDLE pipe = CreateFileW(
L"\\\\.\\pipe\\mypipe",
GENERIC_READ, // only need read access
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (pipe == INVALID_HANDLE_VALUE)
{
wcout << "Failed to connect to pipe." << endl;
// look up error code here using GetLastError()
system("pause");
return 1;
}
wcout << "Reading data from pipe..." << endl;
while (1)
{
// The read operation will block until there is data to read
wchar_t buffer[128];
DWORD numBytesRead = 0;
BOOL result = ReadFile(
pipe,
buffer, // the data from the pipe will be put here
127 * sizeof(wchar_t), // number of bytes allocated
&numBytesRead, // this will store number of bytes actually read
NULL // not using overlapped IO
);
if (result)
{
buffer[numBytesRead / sizeof(wchar_t)] = '\0'; // null terminate the string
wcout << "Number of bytes read: " << numBytesRead << endl;
wcout << "Message: " << buffer << endl;
FlushFileBuffers(pipe);
}
else
{
wcout << "Failed to read data from the pipe." << endl;
wcout << result << endl;
CloseHandle(pipe);
break;
}
}
// Close our pipe handle
wcout << "Done." << endl;
system("pause");
return 0;
}
服务器应该等待客户端连接,然后每隔1秒发送一次定义的消息。
客户端应该能够随时启动/重启。
但每当我启动客户端时,它会收到一次消息,然后在从管道读取时退出并出错。
结果返回0。
更新(对于那些想知道它现在如何工作的人)
这是“更新的”PipeServer代码:
// Open Pipe and wait until ControlProgram is connecting
Pipe.Out = INVALID_HANDLE_VALUE;
DWORD numBytesWritten = 0;
DWORD timerinit = GetTickCount();
bool connected = false;
bool writesucc = false;
bool initial = true;
while (1)
{
DWORD timer = GetTickCount();
wchar_t data[100];
if (!initial)
{
swprintf_s(data, 100, L"Time: %d", timer); // use L"" prefix for wide chars
}
else
{
swprintf_s(data, 100, L"Welcome from your Pipe Server"); // use L"" prefix for wide chars
}
if ((timer - timerinit) > 1000)
{
timerinit = timer;
if (!connected)
{
connected = ConnectNamedPipe(Pipe.Out, NULL);
}
if (connected)
{
writesucc = WriteFile(
Pipe.Out, // handle to our outbound pipe
data, // data to send
wcslen(data) * sizeof(wchar_t), // length of data to send (bytes)
&numBytesWritten, // will store actual amount of data sent
NULL // not using overlapped IO
);
if (writesucc) initial = false;
}
if ((!writesucc) || (Pipe.Out == INVALID_HANDLE_VALUE) || (!connected))
{
initial = true;
CloseHandle(Pipe.Out);
Pipe.Out = INVALID_HANDLE_VALUE;
do
{
Pipe.Out = CreateNamedPipeW(
L"\\\\.\\pipe\\mypipe", // name of the pipe
PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
PIPE_TYPE_BYTE, // send data as a byte stream
1, // only allow 1 instance of this pipe
0, // no outbound buffer
0, // no inbound buffer
0, // use default wait time
NULL // use default security attributes
);
}
while (Pipe.Out == INVALID_HANDLE_VALUE);
}
}
}
答案 0 :(得分:0)
您的客户端失败是因为服务器每秒调用ConnectNamedPipe()
然后在ConnectNamedPipe()
失败时关闭连接,因为已经连接了客户端并且您一次只允许连接1个客户端。这在ConnectNamedPipe()
文档中说明:
命名管道服务器进程可以将ConnectNamedPipe与新创建的管道实例一起使用。 它也可以与之前连接到另一个客户端进程的实例一起使用;在这种情况下,服务器进程必须首先调用DisconnectNamedPipe函数以断开句柄与先前客户端的连接,然后才能将句柄重新连接到新客户端。否则,ConnectNamedPipe返回零,如果先前的客户端已关闭其句柄,则GetLastError返回ERROR_NO_DATA,如果尚未关闭其句柄,则返回ERROR_PIPE_CONNECTED。
您只需编写一次消息 - ConnectNamedPipe()
成功创建新连接时。在此之后你没有循环写作,你的下一次迭代再次调用ConnectNamedPipe()
并失败。
您没有检查来自GetLastError()
的任何错误代码,否则您在阅读文档后会注意到这种情况,以找出错误代码的含义。
尝试更像这样的东西:
const wchar_t *data = L"*** Hello Pipe World ***";
DWORD numBytesWritten;
Pipe.Out = CreateNamedPipeW(
L"\\\\.\\pipe\\mypipe", // name of the pipe
PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
PIPE_TYPE_BYTE, // send data as a byte stream
1, // only allow 1 instance of this pipe
0, // no outbound buffer
0, // no inbound buffer
0, // use default wait time
NULL // use default security attributes
);
if (Pipe.Out == INVALID_HANDLE_VALUE)
{
// error creating pipe
}
else
{
while (should wait for a client to connect)
{
if (!ConnectNamedPipe(Pipe.Out, NULL))
{
// if ERROR_PIPE_CONNECTED then a client is actually connected!
if (GetLastError() != ERROR_PIPE_CONNECTED)
{
// error connecting a client
break;
}
}
DWORD timerinit = GetTickCount();
while (should write to the client)
{
DWORD timer = GetTickCount();
// GetTickCount() wraps back to 0 every 49.7 days, so account for that...
DWORD elapsed = (timer >= timerinit) ? (timer - timerinit) : ((MAXDWORD - timerinit) + timer);
if (elapsed >= 1000)
{
timerinit = timer;
if (!WriteFile(
Pipe.Out, // handle to our outbound pipe
data, // data to send
wcslen(data) * sizeof(wchar_t), // length of data to send (bytes)
&numBytesWritten, // will store actual amount of data sent
NULL // not using overlapped IO
)
{
// error writing to client
break;
}
}
}
DisconnectNamedPipe(Pipe.Out);
}
CloseHandle(Pipe.Out);
}