windows 重新连接到命名管道时出现问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6961240/
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
Problem reconnecting to the named pipe
提问by Ashwin
I have a named pipe server and client. (Doing this in VC++).
我有一个命名管道服务器和客户端。(在 VC++ 中这样做)。
Serverdoes
服务器做
- CreateNamedPipe
- ConnectNamedPipe
- WriteFile
- Disconnect
- Repeat from 2 to 4
- 创建命名管道
- 连接命名管道
- 写文件
- 断开
- 从 2 到 4 重复
Clientdoes
客户做
- CreateFile
- ReadFile
- 创建文件
- 读取文件
The order of execution is as follows,
执行顺序如下,
- Server -- CreateNamedPipe
- Client -- CreateFile
- Server -- ConnectNamedPipe (should return immediately as the client is already connected)
- Server -- WriteFile
- Client -- ReadFile
- Server -- DisconnectNamedPipe
- Client -- CloseHandle
- goto 2
- 服务器 -- CreateNamedPipe
- 客户端——创建文件
- 服务器 -- ConnectNamedPipe(应立即返回,因为客户端已连接)
- 服务器 -- 写文件
- 客户端——读取文件
- 服务器 -- DisconnectNamedPipe
- 客户端——CloseHandle
- 转到 2
This works fine for the first time. However problem occurs when client tries to connects for the second time. When the client tries to connect (CreateFile) for the second time beforethe server did ConnectNamedPipe (but afterdisconnectnamedpipe), it gets ERROR_PIPE_BUSY. It works if client calls createfile after the server calls ConnectNamedPipe.
这是第一次正常工作。但是,当客户端尝试第二次连接时会出现问题。当客户端在服务器执行 ConnectNamedPipe之前(但在断开命名管道之后)第二次尝试连接 (CreateFile) 时,它会收到 ERROR_PIPE_BUSY。如果客户端在服务器调用 ConnectNamedPipe 之后调用 createfile,它会起作用。
Is there anyway that i can get client connected (CreateFile) before server called ConnectNamedPipe (after DisconnectNamedPipe)?
无论如何,我可以在名为 ConnectNamedPipe 的服务器之前(在 DisconnectNamedPipe 之后)连接客户端(CreateFile)吗?
Server code:
服务器代码:
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;
}
}
Client Code:
客户代码:
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);
回答by Carey Gregory
If you get ERROR_PIPE_BUSY on the CreateFile() call in the client, you need to call WaitNamedPipe() and then retry when it returns. If you get a return of zero from WaitNamedPipe() that means it timed out without the pipe becoming available. You'll never see that happen if you pass NMPWAIT_WAIT_FOREVER as the timeout.
如果在客户端的 CreateFile() 调用中得到 ERROR_PIPE_BUSY,则需要调用 WaitNamedPipe(),然后在它返回时重试。如果您从 WaitNamedPipe() 获得零返回,则意味着它在管道不可用的情况下超时。如果您将 NMPWAIT_WAIT_FOREVER 作为超时传递,您将永远不会看到这种情况发生。
You also need to keep in mind that the pipe may become busy again between the time WaitNamedPipe() returns and you call CreateFile(); therefore, you need to do it in a loop. Like this:
您还需要记住,在 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
}
EDIT:
编辑:
I simplified your code and now it works fine. Working server and client follow.
我简化了你的代码,现在它工作正常。工作服务器和客户端跟随。
Server:
服务器:
#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");
}
}
}
Client:
客户:
#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;
}
回答by Divien
On the Server side when you decide to break the connection you must use chain:
在服务器端,当您决定断开连接时,您必须使用链:
1) CloseHandle (Pipe);
2) DisconnectNamedPipe (Pipe);
1)CloseHandle(管道);
2)DisconnectNamedPipe(管道);