繁体   English   中英

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

[英]Problem reconnecting to the named pipe

我有一个命名管道服务器和客户端。 (在VC ++中执行此操作)。

服务器呢

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

客户呢

  1. 的CreateFile
  2. ReadFile的

执行顺序如下,

  1. 服务器 - CreateNamedPipe
  2. 客户端 - CreateFile
  3. 服务器 - ConnectNamedPipe(应该在客户端已连接时立即返回)
  4. 服务器 - WriteFile
  5. 客户端 - ReadFile
  6. 服务器 - DisconnectNamedPipe
  7. 客户端 - CloseHandle
  8. 转到2

这是第一次正常工作。 但是,当客户端尝试第二次连接时会出现问题。 当客户端在服务器执行ConnectNamedPipe 之前第二次尝试连接(CreateFile)时(但 disconnectnamedpipe 之后 ),它将获得ERROR_PIPE_BUSY。 如果客户端在服务器调用ConnectNamedPipe后调用createfile,则它可以工作。

无论如何,我可以在服务器调用ConnectNamedPipe之前连接客户端(CreateFile)(在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);

如果在客户端的CreateFile()调用上获得ERROR_PIPE_BUSY,则需要调用WaitNamedPipe(),然后在返回时重试。 如果从WaitNamedPipe()返回零,这意味着它在没有管道可用的情况下超时。 如果您将NMPWAIT_WAIT_FOREVER作为超时传递,您将永远不会看到这种情况。

您还需要记住,在WaitNamedPipe()返回和调用CreateFile()之间,管道可能会再次忙碌; 因此,你需要在循环中完成它。 像这样:

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
}

编辑:

我简化了你的代码,现在它工作正常。 工作服务器和客户端跟随。

服务器:

#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");
        }
    }
}

客户:

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

在服务器端,当您决定断开连接时,您必须使用链:

1)CloseHandle(管道);

2)DisconnectNamedPipe(Pipe);

暂无
暂无

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

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