Problem reconnecting to named pipe

I have a named pipe and client. (Doing this in VC ++).

Server is running

  • CreateNamedPipe
  • ConnectNamedPipe
  • Writefile
  • Disable
  • Repeat 2 to 4

Customer does

  • 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

This works great for the first time. However, the problem occurs when the client tries to connect a second time. When the client tries to connect (CreateFile) a second time before , the server did ConnectNamedPipe (but after disconnectnamedpipe), it receives ERROR_PIPE_BUSY. It works if the client calls the create file after the server calls ConnectNamedPipe.

Anyway, can I connect to the client (CreateFile) to a server called ConnectNamedPipe (after DisconnectNamedPipe)?

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); 
+6
source share
2 answers

If you get ERROR_PIPE_BUSY in a call to CreateFile () in the client, you need to call WaitNamedPipe () and then try again when it returns. If you get a zero return from WaitNamedPipe (), it means that it was disconnected without the ability to access the pipe. You will never see this happen if you skip NMPWAIT_WAIT_FOREVER as a timeout.

You also need to keep in mind that the pipe may again become busy between the WaitNamedPipe () timeout and CreateFile () is called; so you need to do this in a loop. Like this:

 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. A 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; } 
+8
source

On the server side, when you decide to disconnect, you should use the chain:

1) CloseHandle (Pipe);

2) DisconnectNamedPipe (Pipe);

-2
source

Source: https://habr.com/ru/post/894408/


All Articles