Проблема повторного подключения к именованному каналу

У меня есть сервер и клиент именованного канала. (Выполняется в VC ++.)

Сервер выполняет

  1. CreateNamedPipe
  2. ConnectNamedPipe
  3. WriteFile
  4. Disconnect
  5. Повторяется с 2 по 4

Клиент выполняет

  1. CreateFile
  2. ReadFile

Порядок выполнения следующий:

  1. Сервер - CreateNamedPipe
  2. Клиент - CreateFile
  3. Сервер - ConnectNamedPipe (должен вернуться немедленно, поскольку клиент уже подключен)
  4. Сервер - Файл записи
  5. Клиент - Файл чтения
  6. Сервер - DisconnectNamedPipe
  7. Клиент - CloseHandle
  8. goto 2

Впервые это работает нормально. Однако проблема возникает, когда клиент пытается подключиться во второй раз. Когда клиент пытается подключиться (CreateFile) во второй раз до , сервер выполнил ConnectNamedPipe (но после disconnect namedpipe), он получает ERROR_PIPE_BUSY. Он работает, если клиент вызывает createfile после того, как сервер вызывает ConnectNamedPipe.

Можно ли каким-либо образом подключить клиента (CreateFile) до сервера с именем ConnectNamedPipe (после DisconnectNamedPipe)?

Код сервера:

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);
6
задан Ashwin 6 August 2011 в 07:21
поделиться