如何使用命名管道(C++ 服务器、C# 客户端)

Jkh*_*kh2 4 c# c++ windows ipc named-pipes

我正在尝试开始使用命名管道,因为我将来需要将它们用于我的项目。

目前我有一个 C++ 服务器,它会等待客户端连接并发送测试消息。我大致是按照这个教程开始的。相关代码如下:

    #define MESSAGE L"TestMessage"

HANDLE hnamedPipe = INVALID_HANDLE_VALUE;

hnamedPipe = CreateNamedPipe(
    L"\\\\.\\pipe\\testpipe",
    PIPE_ACCESS_DUPLEX,
    PIPE_TYPE_MESSAGE|
    PIPE_READMODE_MESSAGE|
    PIPE_WAIT,
    PIPE_UNLIMITED_INSTANCES,
    1024,
    1024,
    NMPWAIT_USE_DEFAULT_WAIT,
    NULL);

if(hnamedPipe == INVALID_HANDLE_VALUE)
{
        cout << "Failed" << endl;
}

while(true)
{
    cout<< "Waiting for client"<< endl;

    if(!ConnectNamedPipe(hnamedPipe,NULL))
    {
        if(ERROR_PIPE_CONNECTED != GetLastError())
        {
        cout << "FAIL"<< endl;
        }
    }

    cout<<"Connected!"<<endl;

    //Send over the message
    wchar_t chResponse[] = MESSAGE;
    DWORD cbResponse,cbWritten;
    cbResponse = sizeof(chResponse);

    if(!WriteFile(
    hnamedPipe,
    chResponse,
    cbResponse,
    &cbWritten,
    NULL))
    {
        wprintf(L"failiure w/err 0x%08lx\n",GetLastError);
    }
    cout<<"Sent bytes :)" << endl;
}
Run Code Online (Sandbox Code Playgroud)

客户端代码(C#)如下:

        using (NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut))
        {
            while (true)
            {
                Console.WriteLine("Connecting to server...");
                pipeClient.Connect();

                Console.WriteLine("Connected :)");
                Console.WriteLine(pipeClient.ReadByte());
                pipeClient.Close();
                Console.WriteLine("Closed");
            }

        }
Run Code Online (Sandbox Code Playgroud)

目前我已经让客户端成功连接到服务器并打印出第一个字节。我想知道如何做两件事:

  1. 阅读整个消息 - 我尝试在 pipelineClient 上使用 StreamReader 来读取消息,但它无限期地挂在 ReadLine() 上。

  2. 连续发送消息 - 我希望服务器将一条又一条消息发送到客户端,客户端将一次读取一条消息并将其打印出来。我对 IPC 有点一无所知,所以首先我尝试让客户端在 while(true) 循环中断开连接并重新连接到服务器,而服务器处于 while true 循环中,该循环在顶部总是等待新的客户端连接发送另一条消息。我的尝试在上面的代码中。

任何对此的帮助将不胜感激。最终的目标是将图像从服务器发送到客户端。然后,客户会将它们实时打印到屏幕上。在尝试图像数据之前,我想使用简单的字符串消息来实现此功能。

编辑:

最终,我希望能够从客户端向服务器发送一条消息,指示它想要获取最新的图像帧,然后服务器将发送最新的帧,然后客户端将其显示在屏幕上。所以流程是:

  1. 客户端 -> 服务器:指示客户端想要最新的帧信息。(很简单,可能是一个值为 1 的无符号整数)
  2. 服务器 -> 客户端:最新的帧信息。(640x480 图像存储在具有 RGB 字节值的字节数组中)
  3. 客户端:在显示器上显示框架。

arx*_*arx 5

ReadLine挂起是因为它正在等待换行符,而您的测试消息不包含换行符。

如果您希望服务器连续发送消息,只需在调用中循环即可WriteFile。您无需连接多次。同样在客户端中,将循环放在ReadLine.

如果每条消息都包含以换行符结尾的文本,那么这就足够了,但是如果您确实希望管道客户端在消息模式下工作,您需要调用:

pipeClient.ReadMode = PipeTransmissionMode.Message;
Run Code Online (Sandbox Code Playgroud)

但是,我怀疑这是否能与StreamReader. 相反,您应该使用 来读取单个消息pipeClient.Read

更新

回答你的新问题:

在服务器上,一旦客户端连接就进入一个循环,其中:

  • 服务器从客户端读取数据。这将阻塞,直到客户端请求帧。
  • 服务器发送一个帧。

在客户端上,一旦连接到服务器,就会进入一个循环,其中:

  • 客户端发送“请发送一帧”消息。
  • 客户端从服务器读取数据以获取帧。
  • 客户端显示框架。

我不会使用消息模式管道。如果帧的大小是固定的,那么客户端知道要从服务器读取多少数据。否则,在帧之前添加一个包含其长度的 uint。