我有一个命名管道服务器和客户端。 (在 VC++ 中执行此操作)。
服务器做
- 创建命名管道
- 连接命名管道
- 写文件
- 断开连接
- 从 2 到 4 重复
客户做
- 创建文件
- 读取文件
执行顺序如下,
- 服务器——创建命名管道
- 客户端——创建文件
- Server -- ConnectNamedPipe(应立即返回,因为客户端已连接)
- 服务器——写入文件
- 客户端——读取文件
- 服务器 -- DisconnectNamedPipe
- 客户端——CloseHandle
- 转到2
这是第一次正常工作。但是,当客户端第二次尝试连接时会出现问题。当客户端在服务器执行 ConnectNamedPipe 之前(但之后断开命名管道)第二次尝试连接 (CreateFile) 时,它会收到 ERROR_PIPE_BUSY。如果客户端在服务器调用 ConnectNamedPipe 之后调用 createfile,它就会起作用。
我是否可以在名为 ConnectNamedPipe 的服务器之前(在 DisconnectNamedPipe 之后)连接客户端 (CreateFile)?
服务器代码:
pipe_handle.pipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\testpipe1"),
PIPE_ACCESS_OUTBOUND |
FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFFER_SIZE, // output buffer size
BUFFER_SIZE, // input buffer size
2000, // client time-out
NULL);
if (pipe_handle.pipe == INVALID_HANDLE_VALUE) {
std::cout << "Error while creating pipe" << std::endl;
return -1;
}
std::cout <<"Connecting to named pipe" << std::endl;
std::cout<< "Somebody connected to named pipe" << std::endl;
int ac;
for (ac=0; ac<2; ac++) {
char a[25];
// Wait for some input. This helps me to start the client in other terminal.
cin >> a;
cout << "Connecting..." << endl;
ConnectNamedPipe(pipe_handle.pipe, 0);
cout << "Connect pipe returned." << endl;
// Wait for some input.
cin >> a;
string message = "Test message";
DWORD bytes_written;
if (!WriteFile(pipe_handle.pipe, message.c_str(), message.size(),
&bytes_written, NULL)) {
DWORD er = GetLastError();
char errs[200];
sprintf(errs, "Error : %ld", er);
std::cout << "Error communicating to client.";
std::cout << errs;
}
std::cout << "Written to pipe";
FlushFileBuffers(pipe_handle.pipe);
if (!DisconnectNamedPipe(pipe_handle.pipe)) {
std::cout << "Disconnect failed"<< GetLastError() << endl;
} else {
std::cout << "Disconnect successful"<<endl;
}
}
客户端代码:
while (1) {
std::cout << "Returned" << std::endl;
hPipe = CreateFile(
lpszPipename, // pipe name
GENERIC_READ,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
FILE_FLAG_OVERLAPPED, // default attributes
NULL); // no template file
// Break if the pipe handle is valid.
if (hPipe != INVALID_HANDLE_VALUE)
break;
// Exit if an error other than ERROR_PIPE_BUSY occurs.
if (GetLastError() != ERROR_PIPE_BUSY) {
std::cout<< "Could not open pipe " << GetLastError() << std::endl;
return -1;
}
// All pipe instances are busy, so wait for sometime.
if ( ! WaitNamedPipe(lpszPipename, NMPWAIT_USE_DEFAULT_WAIT)) {
std::cout<< "Could not open pipe: wait timed out." << std::endl;
}
}
OVERLAPPED ol1;
memset(&ol1, 0, sizeof(ol1));
ol1.Offset = 0;
ol1.OffsetHigh = 0;
ol1.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
HANDLE events[1];
events[0] = ol1.hEvent;
cbToWrite = (lstrlen(message)+1)*sizeof(TCHAR);
DWORD bytes_to_read = 2000;
char * buf = reinterpret_cast<char *>(malloc(bytes_to_read));
DWORD bytes_read;
std::cout << "Waiting for read" << std::endl;
bool a = ReadFile(hPipe, buf, bytes_to_read, &bytes_read, &ol1);
if ( ! fSuccess) {
std::cout << "WriteFile to pipe failed. GLE " << GetLastError() << std::endl;
}
std::cout << "Waiting for multiple objects" << std::endl;
WaitForMultipleObjects(1, events, FALSE, INFINITE);
std::cout << "multiple objects returned" << std::endl;
printf("\nMessage sent to server");
CancelIo(hPipe);
CloseHandle(hPipe);
最佳答案
如果您在客户端调用 CreateFile() 时收到 ERROR_PIPE_BUSY,则需要调用 WaitNamedPipe(),然后在它返回时重试。如果您从 WaitNamedPipe() 返回零,这意味着它在管道不可用的情况下超时。如果您将 NMPWAIT_WAIT_FOREVER 作为超时值传递,您将永远不会看到这种情况发生。
您还需要记住,在 WaitNamedPipe() 返回和您调用 CreateFile() 之间,管道可能再次变得繁忙;因此,您需要循环执行。像这样:
while (true)
{
hPipe = CreateFile(pipeName,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hPipe == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_PIPE_BUSY)
{
if (!WaitNamedPipe(pipeName, NMPWAIT_USE_DEFAULT_WAIT))
continue; // timeout, try again
}
else
return false; // error
}
else
break; // success
}
编辑:
我简化了您的代码,现在可以正常工作了。工作服务器和客户端紧随其后。
服务器:
#include <windows.h>
#include <stdio.h>
int main(void)
{
HANDLE pipe;
const DWORD BUFFER_SIZE = 1024;
pipe = CreateNamedPipe("\\\\.\\pipe\\testpipe1",
PIPE_ACCESS_OUTBOUND |
FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFFER_SIZE, // output buffer size
BUFFER_SIZE, // input buffer size
2000, // client time-out
NULL);
if (pipe == INVALID_HANDLE_VALUE)
{
printf("Error while creating pipe\n");
return -1;
}
printf("Connecting to named pipe\n");
int ac;
for (ac=0; ac<2; ac++)
{
// Wait for some input. This helps me to start the client in other terminal.
printf("Connecting...\n");
ConnectNamedPipe(pipe, 0);
printf("Connect pipe returned.\n");
// Wait for some input.
char * message = "Test message";
DWORD bytes_written;
if (!WriteFile(pipe, message, strlen(message)+1, &bytes_written, NULL))
{
DWORD er = GetLastError();
char errs[200];
sprintf_s(errs, "Error : %ld", er);
printf("Error communicating to client.\n");
printf(errs);
}
printf("Written to pipe\n");
FlushFileBuffers(pipe);
if (!DisconnectNamedPipe(pipe))
{
printf("Disconnect failed %d\n", GetLastError());
}
else
{
printf("Disconnect successful\n");
}
}
}
客户:
#include <windows.h>
#include <stdio.h>
int main(void)
{
HANDLE hPipe;
while (1)
{
printf("Returned\n");
hPipe = CreateFile("\\\\.\\pipe\\testpipe1",
GENERIC_READ,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
// Break if the pipe handle is valid.
if (hPipe != INVALID_HANDLE_VALUE)
break;
// Exit if an error other than ERROR_PIPE_BUSY occurs.
if (GetLastError() != ERROR_PIPE_BUSY)
{
printf("Could not open pipe %d\n", GetLastError());
return -1;
}
// All pipe instances are busy, so wait for sometime.
if ( ! WaitNamedPipe("\\\\.\\pipe\\testpipe1", NMPWAIT_USE_DEFAULT_WAIT))
{
printf("Could not open pipe: wait timed out.\n");
}
}
char *message = "hello";
DWORD cbToWrite = (strlen(message)+1)*sizeof(message[0]);
DWORD bytes_to_read = 2000;
char * buf = reinterpret_cast<char *>(malloc(bytes_to_read));
DWORD bytes_read;
printf("Waiting for read\n");
bytes_read = 0;
ReadFile(hPipe, buf, bytes_to_read, &bytes_read, 0);
if (bytes_read <= 0)
{
printf("ReadFile from pipe failed. GLE \n");
}
else
printf("Read %d bytes: %s\n", bytes_read, buf);
CloseHandle(hPipe);
return 0;
}
关于windows - 重新连接到命名管道时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6961240/