windows - Problemer genopretter forbindelse til det navngivne rør

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har en navngivet pipeserver og klient. (Gør dette i VC ++).


Server gør



  1. CreateNamedPipe

  2. ConnectNamedPipe

  3. WriteFile

  4. Afbryd

  5. Gentag fra 2 til 4



Klient gør



  1. CreateFile

  2. ReadFile



Ordren med henrettelse er som følger,



  1. Server - CreateNamedPipe

  2. Klient - CreateFile

  3. Server - ConnectNamedPipe (skal returneres straks, da klienten allerede er tilsluttet)

  4. Server - WriteFile

  5. Klient - ReadFile

  6. Server - DisconnectNamedPipe

  7. Client - CloseHandle

  8. goto 2



Dette virker fint for første gang. Men problemet opstår, når klienten forsøger at forbinde til anden gang. Når klienten forsøger at oprette forbindelse (CreateFile) for anden gang før , gjorde serveren ConnectNamedPipe (men efter frakoblingsnavnet), det bliver ERROR\_PIPE\_BUSY. Det virker, hvis klienten kalder createfile efter at serveren kalder ConnectNamedPipe.


Er der alligevel, at jeg kan få klient tilsluttet (CreateFile) før server kaldet ConnectNamedPipe (efter DisconnectNamedPipe)?


Server kode:


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;
    }
}


Klientkode:


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("
Message sent to server");
CancelIo(hPipe);
CloseHandle(hPipe);

Bedste reference


Hvis du får ERROR\_PIPE\_BUSY på CreateFile () -opkaldet i klienten, skal du ringe WaitNamedPipe () og derefter prøve igen, når den vender tilbage. Hvis du får en retur på nul fra WaitNamedPipe (), betyder det, at det er udløbet, uden at røret bliver tilgængeligt. Du vil aldrig se det ske, hvis du passerer NMPWAIT\_WAIT\_FOREVER som timeout.


Du skal også huske på, at røret kan blive travlt igen mellem tiden WaitNamedPipe () vender tilbage, og du kalder CreateFile (); derfor skal du gøre det i en løkke. Sådan her:


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
}


REDIGERE:


Jeg forenklet din kode og nu fungerer det fint. Arbejdsserver og klient følger.


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
");
        return -1;
    }
    printf("Connecting to named pipe
");

    int ac;

    for (ac=0; ac<2; ac++)
    {
        // Wait for some input. This helps me to start the client in other terminal.
        printf("Connecting...
");

        ConnectNamedPipe(pipe, 0);

        printf("Connect pipe returned.
");

        // 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.
");
            printf(errs);
        }
        printf("Written to pipe
");
        FlushFileBuffers(pipe);
        if (!DisconnectNamedPipe(pipe))
        {
            printf("Disconnect failed \%d
", GetLastError());
        }
        else
        {
            printf("Disconnect successful
");
        }
    }
}


Kunde:


#include <windows.h>
#include <stdio.h>

int main(void)
{
    HANDLE hPipe;

    while (1)
    {

        printf("Returned
");
        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
", 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.
"); 
        }
    }


    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
");
    bytes\_read = 0;
    ReadFile(hPipe, buf, bytes\_to\_read, &bytes\_read, 0);

    if (bytes\_read <= 0)
    {
        printf("ReadFile from pipe failed. GLE 
"); 
    }
    else
        printf("Read \%d bytes: \%s
", bytes\_read, buf);

    CloseHandle(hPipe);
    return 0;
}

Andre referencer 1


På Server side, når du beslutter at bryde forbindelsen, skal du bruge kæde:



  1) CloseHandle (Pipe);

  
  2) DisconnectNamedPipe (Pipe);