之前看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. ElasticSearch.net NEST批量创建修改删除索引完整示例

    本示例采用Elasticsearch+Nest 网上查了很多资料,发现用C#调用Elasticsearch搜索引擎的功能代码很分散,功能不完整,多半是非常简单的操作,没有成型的应用示例.比如新增或修改 ...

  2. java_I/O字节流

    I/O流(Stream) INPUT:输入流,从文件里读OUPUT:输出流,写内容到文件 IO流分为:字符流和字节流 字符流:处理纯文本文件. 字节流:处理可以所有文件. 测试字节输出流OuPut(写 ...

  3. 类型转换:static_cast、reinterpret_cast等

    一.隐式类型转换 系统自动进行,不需要程序开发人员介入. int m = 3 + 45.6;// 48 把小数部分截掉,也属于隐式类型转换的一部分 double b = 3 + 45.6; // 48 ...

  4. SP9098 LCS3

    题目链接 题意分析 \(olinr\) : 序列自动机+一系列的鬼畜操作 相信我 你们没人能切 \(lzxkj\) : \(2^m+vector+\)暴力二分 跑得比你正解还快 首先一看\(m≤5\) ...

  5. leetcode-849-到最近的人的最大距离

    题目描述: 在一排座位( seats)中,1 代表有人坐在座位上,0 代表座位上是空的. 至少有一个空座位,且至少有一人坐在座位上. 亚历克斯希望坐在一个能够使他与离他最近的人之间的距离达到最大化的座 ...

  6. 把一个集合自定转成json字符串

    List<CityData> listData =new List<CityData>(); //把一个集合自定转成json字符串. foreach (var city in ...

  7. Hibernate 连接数据库,数据库返回数据超过限制报错

    1.packet for query is too large 1024 >. you can change this value on the server mysql max_allowed ...

  8. 利用ReentrantLock简单实现一个阻塞队列

    借助juc里的ReentrantLock实现一个阻塞队列结构: package demo.concurrent.lock.queue; import java.util.concurrent.lock ...

  9. 物联网学习之路——IoT概况

    物联网IoT概念 IoT,Internet of Things,即物物相连的互联网.它包含两层意思:一,以互联网为基础:二,物物相连,实现信息的交换和通信.物联网通过智能感知.识别技术与普适计算等通信 ...

  10. ContentProvider和Cursor以及CursorAdapter三者之间内部链接实现原理 解析

    最近 在学习Android3.0中推出的 Loader 机制,其中CursorLoader 这个加载器说是可以实时监测数据和更新数据,为了一探究竟,就连带的将 ContentProvider和Curs ...