之前看wcf服务的时候看到wcf有支持管道通信协议,之前不知道,最近刚好有用到这个,这里写个简单实例

.net有已经封装好的pip通信的对象NamedPipeServerStream 和NamedPipeClientStream对象,底层应该还是调用C++实现的api实现的

对服务端和客户端做个简单的封装方便调用:

server:

public class PipServer:Log
{
public Action<string> ReceiveEvent;
NamedPipeServerStream m_pipServer;
AutoResetEvent monitor = new AutoResetEvent(false);
Thread m_thread;
bool run = true;
string servname; public PipServer(string name)
{
m_pipServer = new NamedPipeServerStream(name,PipeDirection.InOut, , PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
servname = name;
}
public void Listen()
{
try
{
m_thread = new Thread(() =>
{
WaitConnect();
});
m_thread.Start();
}
catch (Exception ex)
{
P(ex, "[PipServer.WaitForConnect]");
}
}
void WaitConnect()
{ AsyncCallback callback = null;
callback = new AsyncCallback(ar =>
{
var pipeServer = (NamedPipeServerStream)ar.AsyncState;
pipeServer.EndWaitForConnection(ar);
Accept();
pipeServer.Disconnect();
m_pipServer.BeginWaitForConnection(callback, m_pipServer);
});
m_pipServer.BeginWaitForConnection(callback, m_pipServer);
} void Accept()
{
try
{ var res = Read();
if(!string.IsNullOrEmpty(res))
ReceiveEvent?.Invoke(res);
}
catch(Exception ex)
{
P(ex, "[PipServer.Accept]");
}
}
public bool Send(string msg)
{
try
{
var buf = Encoding.UTF8.GetBytes(msg);
if (m_pipServer.CanWrite)
{
m_pipServer.Write(buf, , buf.Length);
m_pipServer.Flush();
return true;
}
return false;
}
catch (Exception ex)
{
P(ex, "[PipServer.Send]");
return false;
} } public string Read()
{
try
{
if (m_pipServer.CanRead)
{
int count = ;
List<byte> data = new List<byte>();
byte[] buf = new byte[];
do
{
count=m_pipServer.Read(buf, , buf.Length);
if (count == buf.Length)
{
data.AddRange(buf);
}
else
{
var dst = new byte[count];
Buffer.BlockCopy(buf, , dst, , count);
data.AddRange(dst);
}
} while (count > &&m_pipServer.CanRead);
var res = Encoding.UTF8.GetString(data.ToArray());
return res;
}
return null; }
catch (Exception ex)
{
P(ex, "[PipServer.Read]");
return null;
}
} public void Close()
{
run = false;
m_thread.Join();
if (m_pipServer.IsConnected)
{
m_pipServer.Close();
} }
}

client:

  public class PipClient:Log
{ string serv;
public PipClient(string server)
{
serv = server;
}
public bool Send(string msg)
{
try
{
var buf = Encoding.UTF8.GetBytes(msg);
NamedPipeClientStream pipclient = new NamedPipeClientStream(serv);
pipclient.Connect();
if (pipclient.CanWrite)
{
pipclient.Write(buf, , buf.Length);
pipclient.Flush();
pipclient.Close();
return true;
}
return false;
}
catch (Exception ex)
{
P(ex, "[PipClient.Send]");
return false;
}
}
}

log类写了一个简单日志打印类,集成下方便打印日志,可以直接去掉继承,吧日志打印去掉:

    public class Log
{
public void L(string msg)
{
Console.WriteLine(msg);
}
public void L(string format, params string[] data)
{
Console.WriteLine(string.Format(format,data));
}
public void P(Exception ex, string format, params string[] data)
{
var msg = string.Format(format, data);
Console.WriteLine(string.Format("{0}:{1},{1}", msg, ex.Message, ex.StackTrace));
}
}

调用实例:

 static void  PipTest()
{
Thread thread = new Thread(() =>
{
PipServer pip = new PipServer("TEST_PIP");
pip.ReceiveEvent += s =>
{
w(string.Format("receive:{0}",s));
};
pip.Listen();
});
thread.Start(); bool send = true;
int count = ;
AutoResetEvent monitor = new AutoResetEvent(false);
Thread client = new Thread(() =>
{
PipClient ct = new PipClient("TEST_PIP");
while (send)
{
string msg = string.Format("这是第{0}条数据", count);
w(msg);
ct.Send(msg);
count++;
if (monitor.WaitOne())
{
break;
}
}
});
client.Start();
while (true)
{
var input = Console.ReadLine();
if (input == "q" || input == "Q")
{
send = false;
monitor.Set();
break;
}
}
}

运行时,是客户端向服务端每隔一秒发送一次数据

有几个要注意的点:

1 要注意编码方式,怎么编码就怎么解码,最好是要有固定编码,不要直接写string,因为如果是不同的语言和不同平台实现的类,可能default对应的编码方式是不一样的,这样会造成读取乱码

2 这里可以用streamreader来读取,但是不要用readend这种写法,如果发送方不及时调用close方法,这样写会一直卡住,调用flush也没用

3 这里初始化只传入了servername,实际底层的地址是\\\\.\\pipe\\TEST_PIP,调试的时候下个断点可以看到的,如果用C++写的话,直接调用API传入的地址就是全名,到C#这边会自动被解析

4 可以再传入的信息上做一些文章,加上ID,发送方和接收方,这样可以实现类似回调的功能,这个是支持双向通信的,这里只有单向

5 类库是支持同步和异步的,这里是异步的等待连接,同步的读取,但是貌似没有直接支持4.5await写法的方法,只有AsyncCallback的写法

C# 进程通信-命名管道的更多相关文章

  1. Linux学习笔记(13)-进程通信|命名管道

    匿名管道只能在具有亲属关系的进程间通信,那么如果想要在不具有亲戚关系,想在陌生人之间通信,那又该怎么办呢? 别慌,Linux身为世界上*强大的操作系统,当然提供了这种机制,那便是命名管道-- 所谓命名 ...

  2. 进程通信类型 管道是Linux支持的最初Unix IPC形式之一 命名管道 匿名管道

    管道 Linux环境进程间通信(一) https://www.ibm.com/developerworks/cn/linux/l-ipc/part1/index.html 管道及有名管道 郑彦兴200 ...

  3. Linux下进程通信之管道

    每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把 ...

  4. c# c++通信--命名管道通信

    进程间通信有很多种,windows上面比较简单的有管道通信(匿名管道及命名管道) 最近做个本机c#界面与c++服务进行通信的一个需求.简单用命名管道通信.msdn都直接有demo,详见下方参考. c+ ...

  5. linux下的进程通信之管道与FIFO

    概念:管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息. 优点:不需 ...

  6. Linux进程通信----匿名管道

    Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组表示的文件描述字.这个数组有两个文件描 述字,第一个是用于读数据的文件描述符第二个是用于写数 ...

  7. linux进程通信之管道

    1.介绍: 1)同一主机: unix进程通信方式:无名管道,有名管道,信号 system v方式:信号量,消息队列,共享内存 2)网络通信:Socket,RPC 2.管道: 无名管道(PIPE):使用 ...

  8. 进程通信类型 管道是Linux支持的最初Unix IPC形式之一

    管道 Linux环境进程间通信(一) https://www.ibm.com/developerworks/cn/linux/l-ipc/part1/index.html 管道及有名管道 郑彦兴200 ...

  9. linux 进程通信之 管道和FIFO

    进程间通信:IPC概念 IPC:Interprocess Communication,通过内核提供的缓冲区进行数据交换的机制. IPC通信的方式: pipe:管道(最简单) fifo:有名管道 mma ...

随机推荐

  1. Microsoft Visual C++ 14.0 is required

    building 'twisted.test.raiser' extensionerror: Microsoft Visual C++ 14.0 is required. Get it with &q ...

  2. 如何将Ajax请求从异步改为同步

    Ajax请求默认的都是异步的 如果想同步 async设置为false就可以(默认是true) var html = $.ajax({   url: "some.PHP",   as ...

  3. string、char *的转换

    string转char* 主要有三种方法可以将str转换为char*类型,分别是:data(); c_str(); copy(); data()方法 string str = "hello& ...

  4. 【转载】MDX Step by Step 读书笔记(三) - Understanding Tuples (理解元组)

    1. 在 Analysis Service 分析服务中,Cube (多维数据集) 是以一个多维数据空间来呈现的.在Cube 中,每一个纬度的属性层次结构都形成了一个轴.沿着这个轴,在属性层次结构上的每 ...

  5. CentOS 7 安装过程中设置网络

    如果在安装过程中需要使用网络,需要启动网卡,默认是DHCP 点击configure进入设置 General 常规设置 Automatically connect to this network whe ...

  6. word里的字号与html字号的对应关系

    在word里输入一段文字,把文字调成需要的大小,即"三号或者小三",然后把文件另存为网页,在格式里选择“html”格式,然后把word关闭,将另存的html文件用编辑工具打开,就可 ...

  7. Basic Calculator - Stack(表达式计算器)

    978. Basic Calculator https://www.lintcode.com/problem/basic-calculator/description public class Sol ...

  8. Eclipse 安装spring插件spring tool suite(STS)

    安装方法有2种,一种是在线安装,比较方便,但耗时较长,一种是离线安装,步骤复杂一些,但耗时少,下面请看详细步骤. 方法一:在线安装     1:打开eclipse菜单Help>Eclise Ma ...

  9. [中英对照]Booting Process in Linux RHEL 7 | Linux RHEL 7启动过程

    Booting Process in Linux RHEL 7 | Linux RHEL 7启动过程 In this post, I will guide you booting process in ...

  10. 在Linux上使用C语言编程获取IPv4地址及子网掩码

    在Linux上(如Ubuntu或CentOS), 获取某个Network Interface比如eth0的IP地址等信息,我们可以使用ifconfig或者ip addr show命令. $ ifcon ...