使用命名管道实现进程间通信

创建命名管道

命名管道常常用于应用程序之间的通迅,由于不需要进行序列化和反序列化操作,效率是非常高的。相比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("\r\n\r\n"))
             break;
     }
     else
     {
         if (str == "")
             sb.AppendLine();
         else
             sb.AppendLine(str);
     }
 }

 strAll = strAll.Substring(0, strAll.Length - "\r\n\r\n\r\n".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\r\ndddd\r\n";
                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下载

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏hbbliyong

WCF 学习总结2 -- 配置WCF

前面一篇文章《WCF 学习总结1 -- 简单实例》一股脑儿展示了几种WCF部署方式,其中配置文件(App.config/Web.config)都是IDE自动生成...

32070
来自专栏抠抠空间

Django之admin的使用和源码剖析

19800
来自专栏码农分享

基于百度万年历定制化 2

接着上面的内容,我们本章节通过设置数据库表结构,将json数据通过一种数据结构存储在数据库中。 首先我们需要设计数据库的表。

22520
来自专栏程序员的SOD蜜

PostgreSQL的PDF.NET驱动程序构建过程

目前有两种主要的PostgreSQL的.NET驱动程序,分别是Npgsql和dotConnector for PostgreSQL(以下简称dotConnect...

25570
来自专栏圣杰的专栏

Abp通用配置模块的设计

下面我将尝试用最简单易懂的方式,对Abp源码中通用配置模块的实现方式加以提炼和精简,尽量继承原作者的设计思想,给大家呈现通用配置模块的“最佳实践”。

36710
来自专栏跟着阿笨一起玩NET

[C#] 常用工具类——文件操作类

47430
来自专栏石奈子的Java之路

原 荐 Java9之HttpClientAP

29620
来自专栏Golang语言社区

[Go 语言社区] Golang架构底层---日志函数

服务器后台架构,日志是必不可少的一个功能模块,日志可以分为很多中:统计日志,访问日志,错误日志等 今天大家发是运行中的日志函数 // 日志函数,传入数据为字...

34260
来自专栏.NET开发者社区

一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](四)

上一篇《一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](三)》,我们完成了:

23790
来自专栏空间大数据可视化

利用iframe+from表单实现跨域上传文件

15540

扫码关注云+社区

领取腾讯云代金券