一、前言
最近在做一个这样的功能,Unity
发布PC
平台的客户端exe
,在客户端exe
中拉起浏览器exe
(这个浏览器是自己使用winform
实现的),浏览器内调用JsApi
执行支付,支付结果会回调游戏服务端URL
,服务端通过消息通知客户端exe
,此时客户端exe
通过进程间通信让浏览器exe
关闭。
好了,进程间怎么通信呢?
实现进程间通信有很多中方案:管道(pipe
)、命名管道(FIFO
)、消息队列(MessageQueue
)、共享存储(SharedMemory
)、信号量(Semaphore
)、套接字(Socket
)、信号 ( sinal
)等。
本文要实现的是命名管道的方案。
二、关于命名管道
命名管道又名命名管线(Named Pipes
),是一种简单的进程间通信(IPC
)机制,Microsoft Windows
大都提供了对它的支持(但不包括Windows CE
)。命名管道可在同一台计算机的不同进程之间或在跨越一个网络的不同计算机的不同进程之间,支持可靠的、单向或双向的数据通信。
命名管道的所有实例拥有相同的名称,但是每个实例都有其自己的缓冲区和句柄。
在windows
中命名管道的通信方式是:1、创建命名管道;2、连接命名管道;3读写命名管道。
三、运行效果
四、Demo工程源码
Demo
工程源码我已上传到CODE CHINA
,感兴趣的同学可以下载下来学习。
地址:https://codechina.csdn.net/linxinfa/csharp-namedpipe-demo
五、核心代码
具体代码详见上面的Demo
工程。
服务端
/// <summary>
/// 服务端管道
/// </summary>
class NamedPipeServer
{
private NamedPipeServerStream Server { get; set; }
private byte[] Buffer;
private int BufferSize = 10;
private StringBuilder InputStr { get; set; }
public NamedPipeServer(string name)
{
this.Server = new NamedPipeServerStream(name,
PipeDirection.InOut,
1,
PipeTransmissionMode.Message,
PipeOptions.None);
this.InputStr = new StringBuilder();
Buffer = new byte[BufferSize];
}
public void Start()
{
while (true)
{
this.Server.WaitForConnection();
AsyncState asyncState = new AsyncState()
{
Buffer = new byte[BufferSize],
EvtHandle = new ManualResetEvent(false),
Stream = this.Server
};
//异步读取,并阻塞线程,读取结束取消阻塞
this.Server.BeginRead(this.Buffer, 0, this.Buffer.Length, new AsyncCallback(ReadCallback), asyncState);
asyncState.EvtHandle.WaitOne();
//获取输出字符串
string outStr = "";
if (Readed != null) outStr = this.Readed.Invoke(this.InputStr.ToString().Replace("\0", " ").Trim()).Trim();
this.InputStr.Clear();
for (int i = 0; i < this.BufferSize; i++)
outStr = " " + outStr;
//输出到内存流,然后内存流转写字节码到服务流中
using (MemoryStream memoryStream = new MemoryStream())
using (StreamWriter write = new StreamWriter(memoryStream))
{
write.Write(outStr);
write.Flush();
memoryStream.Flush();
int length = 0;
memoryStream.Position = 0;
byte[] tmp = new byte[BufferSize];
while (((length = memoryStream.Read(tmp, 0, this.Buffer.Length)) != 0))
{
Server.Write(tmp, 0, length);
}
}
Server.WaitForPipeDrain();
Server.Flush();
Server.Disconnect();
}
}
private void ReadCallback(IAsyncResult arg)
{
AsyncState state = arg.AsyncState as AsyncState;
int length = state.Stream.EndRead(arg);
if (length > 0)
{
byte[] buffer;
if (length == BufferSize) buffer = state.Buffer;
else
{
buffer = new byte[length];
Array.Copy(state.Buffer, 0, buffer, 0, length);
}
if (state.MemoryStream == null) state.MemoryStream = new MemoryStream();
state.MemoryStream.Write(buffer, 0, buffer.Length);
state.MemoryStream.Flush();
}
if (length < BufferSize)
{
state.MemoryStream.Position = 0;
using (StreamReader reader = new StreamReader(state.MemoryStream))
{
this.InputStr.Append(reader.ReadToEnd());
}
state.MemoryStream.Close();
state.MemoryStream.Dispose();
state.MemoryStream = null;
state.EvtHandle.Set();
}
else
{
Array.Clear(state.Buffer, 0, BufferSize);
//再次执行异步读取操作
state.Stream.BeginRead(state.Buffer, 0, BufferSize, new AsyncCallback(ReadCallback), state);
}
}
public event Func<string, string> Readed;
}
客户端
/// <summary>
/// 客户端管道
/// </summary>
class NamedPipeClient
{
private NamedPipeClientStream Client { get; set; }
private byte[] Buffer { get; set; }
private bool IsReadEnd { get; set; }
private bool IsWriteEnd { get; set; }
private int BufferSize = 10;
private StringBuilder InputStr { get; set; }
private string OutputStr { get; set; }
public NamedPipeClient(string serverName, string serverHost)
{
Client = new NamedPipeClientStream(serverHost, serverName);
this.Buffer = new byte[BufferSize];
this.InputStr = new StringBuilder();
}
public string Request(string outPutStr)
{
this.OutputStr = outPutStr.Trim();
this.Client.Connect();
for (int i = 0; i < this.BufferSize; i++)
this.OutputStr = " " + this.OutputStr;
using (MemoryStream memoryStream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(memoryStream))
{
writer.Write(OutputStr);
writer.Flush();
memoryStream.Flush();
int length = 0;
memoryStream.Position = 0;
while ((length = memoryStream.Read(Buffer, 0, Buffer.Length)) != 0)
{
this.Client.Write(Buffer, 0, length);
}
this.Client.WaitForPipeDrain();
this.Client.Flush();
}
AsyncState asyncState = new AsyncState()
{
Buffer = new byte[BufferSize],
EvtHandle = new ManualResetEvent(false),
Stream = this.Client
};
IAsyncResult readAsyncResult = this.Client.BeginRead(this.Buffer, 0, this.Buffer.Length, new AsyncCallback(ReadCallback), asyncState);
asyncState.EvtHandle.WaitOne();
this.Client.Close();
this.Client.Dispose();
return this.InputStr.ToString().Replace("\0", " ").Trim();
}
private void ReadCallback(IAsyncResult arg)
{
AsyncState state = arg.AsyncState as AsyncState;
int length = state.Stream.EndRead(arg);
if (length > 0)
{
byte[] buffer;
if (length == BufferSize) buffer = state.Buffer;
else
{
buffer = new byte[length];
Array.Copy(state.Buffer, 0, buffer, 0, length);
}
if (state.MemoryStream == null) state.MemoryStream = new MemoryStream();
state.MemoryStream.Write(buffer, 0, buffer.Length);
state.MemoryStream.Flush();
}
if (length < BufferSize)
{
state.MemoryStream.Position = 0;
using (StreamReader reader = new StreamReader(state.MemoryStream))
{
this.InputStr.Append(reader.ReadToEnd());
}
state.MemoryStream.Close();
state.MemoryStream.Dispose();
state.MemoryStream = null;
state.EvtHandle.Set();
}
else
{
Array.Clear(state.Buffer, 0, BufferSize);
//再次执行异步读取操作
state.Stream.BeginRead(state.Buffer, 0, BufferSize, new AsyncCallback(ReadCallback), state);
}
}
}