消息模式下的 C# 命名管道有时会合并消息?

Posted

技术标签:

【中文标题】消息模式下的 C# 命名管道有时会合并消息?【英文标题】:C# Named Pipes in message mode sometimes merge messages? 【发布时间】:2015-07-20 07:40:21 【问题描述】:

我在我正在处理的项目中使用命名管道,双方都是用 C# 编写的(客户端和服务器),并且都在同一台计算机上(命名管道用于 RPC)。两侧的命名管道设置为使用“PipeTransmissionMode.Message”模式,根据我的理解,应该将传递给 pipe.Write() 的每个数据块“打包”在一条消息中,而 pipe.Read() 在另一端应该会收到整个消息,或者一个都不会。

在尝试反序列化接收端的数据时,我看到我收到了大量数据,比我发送的数据包还要大。于是做了一个小测试,我创建了两个Application,server和client,看起来是这样的:

服务器:

class Program

    static void Main(string[] args)
    
        NamedPipeServerStream pipe = new NamedPipeServerStream("TestPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 1024, 1024);
        pipe.WaitForConnection();

        Random random = new Random();

        while(true)
        
            byte[] buffer = new byte[32];
            random.NextBytes(buffer);
            pipe.Write(buffer, 0, buffer.Length);
            Console.WriteLine(buffer.Length);
        
    

客户:

class Program

    static void Main(string[] args)
    
        NamedPipeClientStream pipe = new NamedPipeClientStream(".", "TestPipe", PipeDirection.InOut, PipeOptions.Asynchronous);
        pipe.Connect();

        while(true)
        
            byte[] buffer = new byte[2048];
            int read = pipe.Read(buffer, 0, buffer.Length);
            Console.WriteLine(read);

            if(read > 32)
               Console.WriteLine("Big");
        
    

运行此程序,服务器仅输出 32(这是我的预期),但客户端有时输出 64,后跟“Big”。怎么回事?

P.S:如果我将 Thread.Sleep(100) 放在服务器循环上,它会按预期工作(两边只写 32)

编辑: 如果我将Thread.Sleep(100) 放在服务器上,Thread.Sleep(200) 放在客户端上,我会更频繁地收到更大的数据包,这使我相信如果在调用 read 之前到达了多个消息,那么 read 将返回所有消息。如何确保每次阅读只返回一条消息?

【问题讨论】:

你不应该将ReadMode 也设置为Message 吗?此外,您还需要在客户端流上进行设置 - 默认情况下,它处于 Byte 模式。 @Luaan NamedPipeClientStream 接受PipeTransmissionMode 的构造函数没有重载,创建后我还没有找到设置它的方法。 ReadMode 有一个设置器 - 它应该在您创建(或连接到)管道之后设置。 @Luaan 不错,看来问题解决了!我还发现您在阅读时需要使用NamedPipeClientStream.IsMessageComplete 以确保您了解所有信息。你能发布一个答案让我接受吗? 【参考方案1】:

您也忘记将ReadMode 设置为Message

pipe.ReadMode = PipeTransmissionMode.Message;

当您创建或连接到管道时,无论TransmissionMode 设置如何,默认模式始终为Byte

【讨论】:

以上是关于消息模式下的 C# 命名管道有时会合并消息?的主要内容,如果未能解决你的问题,请参考以下文章

linux进程间的通信(C): 消息队列

使用命名管道将图像从 C++ 发送到 C# 应用程序

使用命名管道的两种 C++ 到 C# 通信

在c#中使用命名管道在两个进程之间进行双工操作

命名管道中的 C# 死锁

从 VB6 到 WCF 的命名管道