zoukankan      html  css  js  c++  java
  • 使用命名管道实现进程间通信

    创建命名管道

    命名管道常常用于应用程序之间的通迅,由于不需要进行序列化和反序列化操作,效率是非常高的。相比TCP通信方式,效率更高,但比共享内存要低点。
    命名管道可以在本地机器或者局域网内机器实现进程间通信,所以是最佳的通信方式。

    创建一个NamedPipeServerStream:

    NamedPipeServerStream pipeServer = new NamedPipeServerStream(_pipName, PipeDirection.InOut, 10);

    这里表示命名管道服务器的管道放心为双向通信,类似于TCP双工。接着,使用下面的代码等待连接:

    pipeServer.WaitForConnection();

    如果有连接,就可以使用流阅读器进行阅读:

     StreamReader sr = new StreamReader(pipeServer);

    同样,也可以使用流写操作器,将数据写入流,管道的另一端,可以读取这个流:

     using (StreamWriter sw = new StreamWriter(pipeServer))
     {
           sw.AutoFlush = true;
           sw.WriteLine("hello world " + str);
     }

    注意:此处使用了using,意味着写完就会关闭流,但同时也会关闭管道,所以需要注意。假如客户端要读取全部数据,那么需要等到这里关闭流。

    自定义应用层通信协议

    如何读取管道的全部数据,看下面的代码:

     StreamReader sr = new StreamReader(pipeServer);
     string text =sr.ReadToEnd();

    这种方式可以读取全部数据,但是,在管道的另外一段,如果留写操作器不调用 Close方法,这里没法读取完成,程序会阻塞在这里。 所以,必须定义一个“应用协议”,客户端告诉服务端合适结束读取数据。

    我们仿照HTTP协议的方法,使用连续的2个以上的回车换行表示HTTP头信息结束,我们也这样定义,并附加其它标记来表示流数据发送完毕,参考发送端:

     public string Query(string request)
            {
                if (!_pipeClient.IsConnected)
                {
                    _pipeClient.Connect(10000);
                }
    
                StreamWriter sw = new StreamWriter(_pipeClient);
                sw.WriteLine(request);
                sw.WriteLine();//连续2个换行外加"#END"表示结束
                sw.WriteLine();
                sw.WriteLine("#END");
                sw.Flush();
    
                StreamReader sr = new StreamReader(_pipeClient);
                string returnVal = sr.ReadToEnd();
                return returnVal;
            }

    而在服务端,采用下面的方式完成流数据的读取:

    string str = null;
     string strAll = null;
     System.Text.StringBuilder sb = new System.Text.StringBuilder();
    
     StreamReader sr = new StreamReader(pipeServer);
     while (pipeServer.CanRead && (null != (str = sr.ReadLine())))
     {
         
         //当遇到连续2个换行外加#END,表示输入结束
         if (str == "#END" )
         {
             strAll = sb.ToString();
             if (strAll.EndsWith("
    
    "))
                 break;
         }
         else
         {
             if (str == "")
                 sb.AppendLine();
             else
                 sb.AppendLine(str);
         }
     }
    
     strAll = strAll.Substring(0, strAll.Length - "
    
    
    ".Length);

    测试和下载

    最后,写个客户端和服务端控制台程序:

    namespace NamePipedSample_Server
    {
        class Program
        {
            static void Main(string[] args)
            {
                NamedPipeListenServer svr = new NamedPipeListenServer("test");
                svr.Run();
                Console.Read();
            }
        }
    }
    namespace NamePipedSample_Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                string sendStr = null;
                using (NamedPipeClient client = new NamedPipeClient(".", "test"))
                {
                    sendStr = "fff
    dddd
    ";
                    Console.WriteLine("send:{0}",sendStr);
                    Console.WriteLine("Reply:{0}",client.Query(sendStr));
    
                    sendStr = "54353";
                    Console.WriteLine("send:{0}", sendStr);
                    Console.WriteLine("Reply:{0}", client.Query(sendStr));
    
                    sendStr = "aaaaaaa";
                    Console.WriteLine("send:{0}", sendStr);
                    Console.WriteLine("Reply:{0}", client.Query(sendStr));
                }
                Console.WriteLine("send all ok.");
                Console.Read();
            }
        }
    }

     跨机器使用命名管道


    上面的程序在本地机器使用没问题的,但是跨机器可能会遇到问题,在使用的时候,需要将主机名字 "." 替换成
    实际的局域网主机名字,例如:

    using (NamedPipeClient client = new NamedPipeClient("user-xxxPc", "test"))
    {
     //
    }

    但是这样可能还是无法访问,会报下面的错误:

    “System.IO.IOException”类型的未经处理的异常在 System.Core.dll 中发生 
    
    其他信息: 登录失败: 未知的用户名或错误密码。

    此时需要在客户机器上,地址栏里面输入下面的地址: \user-xxxPc

    此时会提示输入用户名,密码,最后勾选 “记住账号”,下次即可使用了。

    经过测试,这种方法是先命名管道客户端-服务器通信成功。 本文程序是在网友原来文章的基础上改进的,在此表示感谢,原文地址:  http://blog.csdn.net/educast/article/details/7219774

    本文程序Demo下载

  • 相关阅读:
    实验二
    2
    DS博客作业08--课程总结
    DS博客作业07--查找
    DS博客作业06--图
    DS博客园作业05--树
    有向图强连通分量Tarjan算法
    nyoj 题目737 合并石子(一)
    nyoj 题目61 传纸条
    nyoj 题目49 开心的小明
  • 原文地址:https://www.cnblogs.com/bluedoctor/p/4671086.html
Copyright © 2011-2022 走看看