應答式進程間通信

全體

  • 應答式是指服務端開啟管道連接并等待連接,客戶端寫入請求,服務端讀取請求,處理后寫入應答,客戶端讀取應答。最后關閉管道。
  • 通信數據為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);
           }
       }
   }