命名管道 CreateFile() 返回 INVALID_HANDLE_VALUE,GetLastError() 返回 ERROR_PIPE_BUSY
Posted
技术标签:
【中文标题】命名管道 CreateFile() 返回 INVALID_HANDLE_VALUE,GetLastError() 返回 ERROR_PIPE_BUSY【英文标题】:Named Pipe CreateFile() returns INVALID_HANDLE_VALUE, and GetLastError() returns ERROR_PIPE_BUSY 【发布时间】:2011-12-16 02:40:16 【问题描述】:我编写了一个类来处理命名管道连接,如果我创建一个实例,关闭它,然后尝试创建另一个实例,对CreateFile()
的调用返回INVALID_HANDLE_VALUE
,GetLastError()
返回ERROR_PIPE_BUSY
.这里发生了什么?我该怎么做才能确保对Connect()
的调用成功?
PipeAsync A, B;
A.Connect("\\\\.\\pipe\\test",5000);
A.Close();
cout << GetLastError(); // some random value
B.Connect("\\\\.\\pipe\\test",5000);
cout << GetLastError(); // 231 (ERROR_PIPE_BUSY)
B.Close();
这是我对Connect()
和Close()
的实现
BOOL PipeAsync::Connect(LPCSTR pszPipeName, DWORD dwTimeout)
this->pszPipeName = pszPipeName;
this->fExisting = TRUE;
DWORD dwMode = this->fMessageMode ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE;
hPipe = CreateFile(
this->pszPipeName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if( INVALID_HANDLE_VALUE == hPipe )
return FALSE; /* set break point here ; breaks here on second call to Connect() */
if( GetLastError() == ERROR_PIPE_BUSY )
if(!WaitNamedPipe( this->pszPipeName, dwTimeout ))
return FALSE; /* set break point here */
if( !SetNamedPipeHandleState( hPipe, &dwMode, NULL, NULL ) )
return FALSE; /* set break point here */
return TRUE;
VOID PipeAsync::Close()
if( fExisting )
DisconnectNamedPipe( hPipe );
CloseHandle( hPipe );
编辑:我忘了告诉你我是如何得出结论的......我设置了 cmets 中指示的断点。运行时,它会在第一个断点处停止。
编辑:这是我更新的代码
if( INVALID_HANDLE_VALUE == hPipe )
if( GetLastError() == ERROR_PIPE_BUSY )
if(!WaitNamedPipe( this->pszPipeName, dwTimeout ))
return FALSE; /* break-point: breaks here on second call */
else
return FALSE; /* break-point /*
现在,WaitNamedPipe()
在第二次调用 Connect()
时返回 false,而 GetLastError()
返回 2,或者 ERROR_FILE_NOT_FOUND
?
【问题讨论】:
忠告:\\
、\p
和 \t
将被解释为转义字符。切换到正斜杠或双反斜杠以“转义”:"\\\\.\\pipe\\test"
.
这是一个错字...我更正了...
【参考方案1】:
来自Named Pipe Client:
如果管道存在但它的所有实例都忙,则 CreateFile 返回 INVALID_HANDLE_VALUE 并且 GetLastError 函数返回 ERROR_PIPE_BUSY。发生这种情况时,命名管道客户端使用 WaitNamedPipe 函数等待命名管道的实例 变得可用。
该链接有处理ERROR_PIPE_BUSY
的示例代码。
编辑:
演示在命名管道上接受和连接的小型可编译示例:
const char* const PIPE_NAME = "\\\\.\\pipe\\test";
const int MAX_CONNECTIONS = 10;
void client_main()
DWORD last_error;
unsigned int elapsed_seconds = 0;
const unsigned int timeout_seconds = 5;
HANDLE handle = CreateFile(PIPE_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
while (INVALID_HANDLE_VALUE == handle &&
elapsed_seconds < timeout_seconds)
last_error = GetLastError();
if (last_error != ERROR_PIPE_BUSY)
break;
Sleep(1 * 1000);
elapsed_seconds++;
handle = CreateFile(PIPE_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == handle)
std::cerr << "Failed to connect to pipe " << PIPE_NAME <<
": last_error=" << last_error << "\n";
else
std::cout << "Connected to pipe " << PIPE_NAME << "\n";
CloseHandle(handle);
HANDLE _get_server_handle()
// Error handling omitted for security descriptor creation.
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, static_cast<PACL>(0), FALSE);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
// Create a bi-directional message pipe.
HANDLE handle = CreateNamedPipe(PIPE_NAME,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_NOWAIT,
PIPE_UNLIMITED_INSTANCES,
4096,
4096,
0,
&sa);
if (INVALID_HANDLE_VALUE == handle)
std::cerr << "Failed to create named pipe handle: last_error=" <<
GetLastError() << "\n";
return handle;
void server_main()
HANDLE handle = _get_server_handle();
if (INVALID_HANDLE_VALUE != handle)
int count = 0;
while (count < MAX_CONNECTIONS)
BOOL result = ConnectNamedPipe(handle, 0);
const DWORD last_error = GetLastError();
if (ERROR_NO_DATA == last_error)
count++;
std::cout << "A client connected and disconnected: count=" <<
count << "\n";
CloseHandle(handle);
handle = _get_server_handle();
else if (ERROR_PIPE_CONNECTED == last_error)
count++;
std::cout << "A client connected before call to " <<
"ConnectNamedPipe(): count=" << count << "\n";
CloseHandle(handle);
handle = _get_server_handle();
else if (ERROR_PIPE_LISTENING != last_error)
std::cerr << "Failed to wait for connection: last_error=" <<
GetLastError() << "\n";
CloseHandle(handle);
break;
Sleep(100);
int main(int a_argc, char** a_argv)
if (2 == a_argc)
if (std::string("client") == *(a_argv + 1))
for (int i = 0; i < MAX_CONNECTIONS; i++)
client_main();
else if (std::string("server") == *(a_argv + 1))
server_main();
return 0;
先执行服务端:
pipetest.exe server
然后执行客户端:
pipetest.exe client
我无法从发布的代码中看出问题所在。希望这个小例子能帮助您找到问题。
【讨论】:
我改变了我的代码以遵循这个逻辑,现在WaitNamedPipe()
返回false,GetLastError()返回ERROR_FILE_NOT_FOUND
我还尝试了 MSDN 示例中的循环逻辑,得到了相同的结果。 CreateFile()
返回INVALID_HANDLE_VALUE
,然后GetLastError()
返回ERROR_PIPE_BUSY
,WaitNamedPipe()
返回FALSE
,GetLastError()
返回ERROR_FILE_NOT_FOUND
。
您是否创建了名为“\\\\.\\pipe\\test”的命名管道?正在使用 CreateNamedPipe() 创建命名管道。
是的。此代码来自客户端应用程序。 A client process connects to a named pipe by using the CreateFile
“可编译的小例子”没有说明这一点。它错误地调用Sleep()
而不是WaitNamedPipe()
。以上是关于命名管道 CreateFile() 返回 INVALID_HANDLE_VALUE,GetLastError() 返回 ERROR_PIPE_BUSY的主要内容,如果未能解决你的问题,请参考以下文章