应答式进程间通信

全体

  • 应答式是指服务端开启管道连接并等待连接,客户端写入请求,服务端读取请求,处理后写入应答,客户端读取应答。最后关闭管道。
  • 通信数据为XML形式,写入管道前将对象XML序列化,读取时XML反序列化得到对象。
  • 使用XML的原因为.net版本较低,不使用第三方库则不支持JSON,不得以使用。虽然JSON使用更为方便。
  • 由于管道为最后关闭,所以服务端在读取请求时,不能读到最后,否则将继续等待客户端继续写入,而客户端并不再写入,最终服务端线程停留在等待客户端写入而阻塞。
  • 所以管道中的写入与读取时,使用WriteLine和ReadLine,每次只写一行,读一行。XML序列化时,取消掉所有的换行。
  • WriteLine方法中将字符串写入该流,后跟行结束符(换行符)。所以读取一行并没有读到末尾。

服务端

public class NPipeServer
{
    private const string pipeName = "MyPipe"; // 定义管道名称
    public void Start()
    {
        while (true)
        {
            try {
                using (var server = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous))
                {
                    Console.WriteLine("服务器已启动,等待连接...");
                    server.WaitForConnection();

                    using (StreamWriter writer = new StreamWriter(server))
                    using (StreamReader reader = new StreamReader(server))
                    {
                        string request = reader.ReadLine();

                        Console.WriteLine("收到客户端消息: " + request);

                        MyObject myObject = MyObject.DeserializeFromXml(request);

                        // 处理请求并准备应答
                        string response = ProcessRequest(request);

                        // 将应答写回给客户端
                        writer.WriteLine(response);
                        writer.Flush();
                    }
                }
            } catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            
        }

    }

    private static string ProcessRequest(string request)
    {
        // 在这里实现处理逻辑,比如计算、查询数据库等
        return $"已处理您的请求:{request},这里是应答...";
    }
}

客户端

    public class NPipeClient
    {
        private const string pipeName = "MyPipe";

        public void SendRequest(MyObject myObject)
        {
            try {
                using (var client = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut))
                {
                    client.Connect(5000); // 等待最多5秒连接到服务器

                    using (StreamWriter writer = new StreamWriter(client))
                    using (StreamReader reader = new StreamReader(client))
                    {
                        // 发送请求
                        writer.WriteLine(myObject.SerializeToXml());
                        writer.Flush();

                        // 接收应答
                        string response = reader.ReadLine();
                        Console.WriteLine("从服务器接收到应答: " + response);
                    }
                }
            } catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

        }
    }

通信数据

   [Serializable]
   public class MyObject
   {
       public string Msg { get; set; }
       public int Data { get; set; }

       public string SerializeToXml()
       {
           var serializer = new XmlSerializer(typeof(MyObject));
           var settings = new XmlWriterSettings
           {
               OmitXmlDeclaration = true,
               NewLineHandling = NewLineHandling.None,
               Encoding = Encoding.UTF8
           };

           XmlSerializerNamespaces _namespaces = new XmlSerializerNamespaces(
   new XmlQualifiedName[] {
                       new XmlQualifiedName(string.Empty, "aa")
});
           using (var stringWriter = new StringWriter())
           using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
           {
               serializer.Serialize(xmlWriter, this, _namespaces);
               string xmlString = stringWriter.ToString().Replace(@"\r\n","").Replace(@"\n","");

               return xmlString;
           }
       }

       public static MyObject DeserializeFromXml(string xml)
       {
           var serializer = new XmlSerializer(typeof(MyObject));
           using (var textReader = new StringReader(xml))
           {
               return (MyObject)serializer.Deserialize(textReader);
           }
       }
   }