简体   繁体   English

重新连接到命名管道时出现问题

[英]Problem reconnecting to the named pipe

I have a named pipe server and client. 我有一个命名管道服务器和客户端。 (Doing this in VC++). (在VC ++中执行此操作)。

Server does 服务器呢

  1. CreateNamedPipe CreateNamedPipe时
  2. ConnectNamedPipe ConnectNamedPipe
  3. WriteFile WriteFile的
  4. Disconnect 断开
  5. Repeat from 2 to 4 重复2到4

Client does 客户呢

  1. CreateFile 的CreateFile
  2. ReadFile ReadFile的

The order of execution is as follows, 执行顺序如下,

  1. Server -- CreateNamedPipe 服务器 - CreateNamedPipe
  2. Client -- CreateFile 客户端 - CreateFile
  3. Server -- ConnectNamedPipe (should return immediately as the client is already connected) 服务器 - ConnectNamedPipe(应该在客户端已连接时立即返回)
  4. Server -- WriteFile 服务器 - WriteFile
  5. Client -- ReadFile 客户端 - ReadFile
  6. Server -- DisconnectNamedPipe 服务器 - DisconnectNamedPipe
  7. Client -- CloseHandle 客户端 - CloseHandle
  8. goto 2 转到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 before the server did ConnectNamedPipe (but after disconnectnamedpipe), it gets ERROR_PIPE_BUSY. 当客户端在服务器执行ConnectNamedPipe 之前第二次尝试连接(CreateFile)时(但 disconnectnamedpipe 之后 ),它将获得ERROR_PIPE_BUSY。 It works if client calls createfile after the server calls ConnectNamedPipe. 如果客户端在服务器调用ConnectNamedPipe后调用createfile,则它可以工作。

Is there anyway that i can get client connected (CreateFile) before server called ConnectNamedPipe (after DisconnectNamedPipe)? 无论如何,我可以在服务器调用ConnectNamedPipe之前连接客户端(CreateFile)(在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);

If you get ERROR_PIPE_BUSY on the CreateFile() call in the client, you need to call WaitNamedPipe() and then retry when it returns. 如果在客户端的CreateFile()调用上获得ERROR_PIPE_BUSY,则需要调用WaitNamedPipe(),然后在返回时重试。 If you get a return of zero from WaitNamedPipe() that means it timed out without the pipe becoming available. 如果从WaitNamedPipe()返回零,这意味着它在没有管道可用的情况下超时。 You'll never see that happen if you pass NMPWAIT_WAIT_FOREVER as the timeout. 如果您将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(); 您还需要记住,在WaitNamedPipe()返回和调用CreateFile()之间,管道可能会再次忙碌; therefore, you need to do it 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. 我简化了你的代码,现在它工作正常。 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;
}

On the Server side when you decide to break the connection you must use chain: 在服务器端,当您决定断开连接时,您必须使用链:

1) CloseHandle (Pipe); 1)CloseHandle(管道);

2) DisconnectNamedPipe (Pipe); 2)DisconnectNamedPipe(Pipe);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM