天天看點

C# 命名管道通信

命名管道(NamedPipe)是伺服器程序和一個或多個客戶程序之間通信的單向或雙向管道。不同于匿名管道的是:命名管道可以在不相關的程序之間和不同計算機之間使用,伺服器建立命名管道時給它指定一個名字,任何程序都可以通過該名字打開管道的另一端,根據給定的權限和伺服器程序通信。命名管道提供了相對簡單的程式設計接口,使通過網絡傳輸資料并不比同一計算機上兩程序之間通信更困難,不過如果要同時和多個程序通信它就力不從心了。

最近做項目需要在C++和C#程式之間進行通信,查了好多資料,本來覺得挺複雜,其實弄明白之後很簡單。C++與C#都是Windows平台的,進行管道通信其實都是調用系統API隻不過都是封裝好了的,兩者之間寫的通信都是相通的,隻要建立的管道名相同即可。比如用C++建立出服務端C++Sever和用戶端C++Cliet,他們之間可以直接收發消息,同時C#建立出服務端C#Sever和用戶端C#Cliet可以互相發消息。都實作之後,用C++Sever和C#Client組合或者C++Client和C#Sever組合使用基本是沒有問題的,可能傳輸時有字元編碼問題,可以調試解決。以下是我寫的C#服務端和用戶端的兩個控制台程式。

服務端:

class Program
    {
        static void Main(string[] args)
        {
            WaitData();
        }
        private static void WaitData()
        {
            using (NamedPipeServerStream pipeServer = new NamedPipeServerStream("mynamedpipe", PipeDirection.InOut, ))//建立管道
            {
                try
                {
                    pipeServer.WaitForConnection();//等待用戶端連接配接
                    pipeServer.ReadMode = PipeTransmissionMode.Byte;
                    Console.WriteLine("sucess connected?"+pipeServer.IsConnected);
                    StreamReader sr = new StreamReader(pipeServer);//擷取管道輸入流
                    StreamWriter sw = new StreamWriter(pipeServer);//擷取管道輸出流
                    string result; 
                    while (true)//循環接收用戶端消息
                    {
                        result = sr.ReadLine();
                        if (result == null || result == "bye")
                            break;
                        Console.WriteLine(result);
                        sw.WriteLine("I'm Sever!");//傳回用戶端資訊
                        sw.Flush();//清除緩存流,注意必須有這一步,否則會造成管道堵塞
                    }                 
                    Console.ReadKey();    
                }
                catch (IOException e)
                {
                    throw e;
                }
            }
        }
    }
           

用戶端:

class Program
    {
        static void Main(string[] args)
        {
            StartClient();
            Console.ReadKey();
        }
        public static void StartClient()
        {
            string input;         
            try
            {
                using (NamedPipeClientStream pipeStream = new NamedPipeClientStream("localhost", "mynamedpipe"))//與服務端管道名一緻,如果連接配接C++服務端,名稱一緻即可,“localhost”可以更換為IP位址,也可以進行網絡通信
                {
                    pipeStream.Connect();//連接配接服務端
                    if (!pipeStream.IsConnected)
                    {
                        Console.WriteLine("Failed to connect ....");
                        return;
                    }
                    StreamWriter sw = new StreamWriter(pipeStream);
                    StreamReader sr = new StreamReader(pipeStream);
                    while (true)//循環輸入
                    {
                        input = Console.ReadLine();
                        Console.WriteLine("SendMessage:" + input);
                        sw.WriteLine(input);//傳遞消息到服務端
                        sw.Flush();//注意一定要有,同服務端一樣
                        string temp = "";
                        temp = sr.ReadLine();//擷取服務端傳回資訊
                        Console.WriteLine("replyContent:" + temp );
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message+"\n"+e.StackTrace);
            }         
        }
    }
           
需要注意的問題:
1.管道通信為半雙工通信,資訊的進出都是從一個管道進出,類似對講機,資訊要麼進要麼出,有時候寫不好就會造成阻塞,是以往流裡面寫完東西需要flush().
2.如果C++與C#通信,C++沒有flush()函數,在傳遞的字元串中加上\n即可.
3.傳輸過程注意編碼問題.