採用管道進行通訊的例子
作者:肖波
用Remoting做程式間通訊,效率較低,於是做了一個採用管道技術進行程式間通訊的例子,在1.8G 雙核計算機上每秒鐘可以傳送180M資料。下面給出原始碼
Server端的管道類
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Pipe.Win32;
namespace Pipe.Server
{
public delegate void ReceiveMessageFunc(System.IO.MemoryStream m);
public delegate void ReceiveMessageErrorFunc(Exception e);
public class PipeServer : IDisposable
{
enum State
{
Idle = 0,
Begining = 1,
Reading = 2,
}
String m_PipeName;
uint m_Handle;
uint m_BufferSize;
State m_State = State.Idle;
const ulong SYNC_HEAD = 0xf8c7a1ca13db307e;
const uint NMPWAIT_USE_DEFAULT_WAIT = 0x00000000;
const int DEFAULT_BUFFER_SIZE = 1024;
ReceiveMessageFunc m_ReceiveMessage;
ReceiveMessageErrorFunc m_ReceiveMessageError;
public ReceiveMessageFunc OnReceiveMessage
{
get
{
return m_ReceiveMessage;
}
set
{
m_ReceiveMessage = value;
}
}
public ReceiveMessageErrorFunc OnReceiveMessageError
{
get
{
return m_ReceiveMessageError;
}
set
{
m_ReceiveMessageError = value;
}
}
public String PipeName
{
get
{
return m_PipeName;
}
}
public uint BufferSize
{
get
{
return m_BufferSize;
}
}
public String PipeUri
{
get
{
return @"\\.\pipe\" + m_PipeName;
}
}
private bool IsSyncHead(byte[] buf, uint len, out int msgLen)
{
msgLen = 0;
if (len != 12)
{
return false;
}
if (SYNC_HEAD != BitConverter.ToUInt64(buf, 0))
{
return false;
}
msgLen = BitConverter.ToInt32(buf, sizeof(ulong));
if (msgLen < 0)
{
return false;
}
return true;
}
private void ProcessMessage(System.IO.MemoryStream m)
{
if (OnReceiveMessage != null)
{
m.Position = 0;
OnReceiveMessage(m);
}
}
private void ThreadProc()
{
}
public PipeServer(String pipeName)
{
m_PipeName = pipeName;
m_BufferSize = DEFAULT_BUFFER_SIZE;
}
public PipeServer(String pipeName, uint bufferSize)
{
m_PipeName = pipeName;
m_BufferSize = bufferSize;
}
public void Listen()
{
while (true)
{
try
{
m_Handle = NTKernel.CreateNamedPipe(PipeUri, (uint)FileAccess.PIPE_ACCESS_DUPLEX,
(uint)PipeMode.PIPE_READMODE_MESSAGE | (uint)PipeMode.PIPE_TYPE_MESSAGE | (uint)PipeMode.PIPE_WAIT,
NTKernel.PIPE_UNLIMITED_INSTANCES, m_BufferSize, m_BufferSize, NMPWAIT_USE_DEFAULT_WAIT, new SecurityAttributes());
if (m_Handle == NTKernel.INVAILD_HANDLE)
{
throw new Exception(String.Format("CreateNamedPipe fail, err={0}", NTKernel.GetLastError()));
}
if (!NTKernel.ConnectNamedPipe(m_Handle, IntPtr.Zero))
{
uint err = NTKernel.GetLastError();
NTKernel.CloseHandle(m_Handle);
throw new Exception(String.Format("ConnectNamedPipe fail, err={0}", err));
}
byte[] buf = new byte[m_BufferSize];
uint relSize = 0;
int msgLen = 0;
int offset = 0;
System.IO.MemoryStream m = new System.IO.MemoryStream();
while (NTKernel.ReadFile(m_Handle, buf, m_BufferSize, out relSize, IntPtr.Zero))
{
switch (m_State)
{
case State.Idle:
if (IsSyncHead(buf, relSize, out msgLen))
{
m_State = State.Begining;
}
break;
case State.Begining:
offset = 0;
m = new System.IO.MemoryStream();
m.Write(buf, 0, (int)relSize);
offset += (int)relSize;
if (offset >= msgLen)
{
m_State = State.Idle;
if (offset == msgLen)
{
ProcessMessage(m);
}
else
{
if (OnReceiveMessageError != null)
{
OnReceiveMessageError(new Exception("Message overflow!"));
}
}
}
else
{
m_State = State.Reading;
}
break;
case State.Reading:
m.Write(buf, 0, (int)relSize);
offset += (int)relSize;
if (offset >= msgLen)
{
m_State = State.Idle;
if (offset == msgLen)
{
ProcessMessage(m);
}
else
{
if (OnReceiveMessageError != null)
{
OnReceiveMessageError(new Exception("Message overflow!"));
}
}
}
break;
}
}
NTKernel.DisconnectNamedPipe(m_Handle);
NTKernel.CloseHandle(m_Handle);
System.Threading.Thread.Sleep(10);
}
catch (Exception e)
{
if (OnReceiveMessageError != null)
{
OnReceiveMessageError(e);
}
}
}
}
public void Dispose()
{
lock (this)
{
if (m_Handle != NTKernel.INVAILD_HANDLE)
{
NTKernel.CloseHandle(m_Handle);
m_Handle = NTKernel.INVAILD_HANDLE;
}
}
}
~PipeServer()
{
Dispose();
}
}
}
Client 端的管道類
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Pipe.Win32;
namespace Pipe.Client
{
public class PipeClient : IDisposable
{
String m_PipeName;
String m_ComputerName;
uint m_Handle;
uint m_BufferSize;
const ulong SYNC_HEAD = 0xf8c7a1ca13db307e;
byte[] m_SendBuf;
Propertys
private void Connect()
{
int file_not_find_times = 0;
while (true)
{
m_Handle = NTKernel.CreateFile(PipeUri, (uint)FileAccess.GENERIC_READ | (uint)FileAccess.GENERIC_WRITE,
0, new SecurityAttributes(), (uint)CreateMode.OPEN_EXISTING, 0, 0);
if (m_Handle == NTKernel.INVAILD_HANDLE)
{
uint err = NTKernel.GetLastError();
if (err == NTKernel.ERROR_FILE_NOT_FOUND)
{
if (file_not_find_times++ < 2000)
{
System.Threading.Thread.Sleep(20);
continue;
}
}
if (err == NTKernel.ERROR_PIPE_BUSY)
{
NTKernel.WaitNamedPipeA(PipeUri, 20);
continue;
}
else
{
throw new Exception(String.Format("Create File for pipe fail, err={0}", NTKernel.GetLastError()));
}
}
break;
}
}
private void WriteBuf(byte[] buf)
{
uint relSize;
if (!NTKernel.WriteFile(m_Handle, buf, (uint)buf.Length, out relSize, IntPtr.Zero))
{
throw new Exception(String.Format("Send message to pipe fail, err={0}", NTKernel.GetLastError()));
}
}
public void Close()
{
lock (this)
{
if (m_Handle != NTKernel.INVAILD_HANDLE)
{
bool ret = NTKernel.CloseHandle(m_Handle);
m_Handle = NTKernel.INVAILD_HANDLE;
}
}
}
public PipeClient(String pipeName, uint bufferSize)
{
m_PipeName = pipeName;
m_BufferSize = bufferSize;
m_Handle = NTKernel.INVAILD_HANDLE;
m_SendBuf = new byte[bufferSize];
}
public void Dispose()
{
Close();
}
public void Send(byte[] buf)
{
if (m_Handle == NTKernel.INVAILD_HANDLE)
{
Connect();
}
//Build Message Head
byte[] syncHead = BitConverter.GetBytes(SYNC_HEAD);
byte[] length = BitConverter.GetBytes(buf.Length);
byte[] lengthBuf = new byte[syncHead.Length + length.Length];
syncHead.CopyTo(lengthBuf, 0);
for (int i = syncHead.Length; i < lengthBuf.Length; i++)
{
lengthBuf[i] = length[i - syncHead.Length];
}
WriteBuf(lengthBuf);
//write content
if (buf.Length < m_BufferSize)
{
WriteBuf(buf);
}
else
{
//the length of buf lardge than m_BufferSize
int offset = 0;
int len = Math.Min((int)m_BufferSize, buf.Length - offset);
byte[] sendbuf;
while (len > 0)
{
if (len == m_BufferSize)
{
sendbuf = m_SendBuf;
}
else
{
sendbuf = new byte[len];
}
System.IO.MemoryStream m = new System.IO.MemoryStream(sendbuf);
m.Write(buf, offset, len);
m.Close();
offset += len;
len = Math.Min((int)m_BufferSize, buf.Length - offset);
WriteBuf(sendbuf);
}
}
}
~PipeClient()
{
Dispose();
}
}
}
NTKernel.cs
這個程式檔案Client 和 Server 都要,封裝了相應的API函式
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace Pipe.Win32
{
Data Structures
public class NTKernel
{
public const uint PIPE_UNLIMITED_INSTANCES = 255;
public const uint INVAILD_HANDLE = 0xFFFFFFFF;
public const uint ERROR_FILE_NOT_FOUND = 2;
public const uint ERROR_PIPE_BUSY = 231;
internal const uint INFINITE = 0xFFFFFFFF;
[DllImport("kernel32", EntryPoint = "GetLastError", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint GetLastError();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint CreateNamedPipe(string lpName, uint dwOpenMode,
uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize,
uint nDefaultTimeOut, SecurityAttributes lpSecurityAttributes);
[DllImport("kernel32.dll")]
public static extern bool ConnectNamedPipe(uint hNamedPipe,
IntPtr lpOverlapped);
[DllImport("kernel32.dll")]
public static extern bool DisconnectNamedPipe(uint hNamedPipe);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern int WaitNamedPipeA (string lpNamedPipeName, int nTimeOut);
[DllImport("kernel32.dll")]
public static extern bool ReadFile(uint hFile, byte[] lpBuffer,
uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
[DllImport("kernel32.dll")]
public static extern bool WriteFile(uint hFile, byte[] lpBuffer,
uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(uint hHandle);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern uint CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
SecurityAttributes lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
int hTemplateFile
);
Mutex
Semaphore
Event
}
class Mutex : IDisposable
{
IntPtr m_Handle;
public Mutex(SecurityAttributes lpEventAttributes, bool bInitialOwner, string lpName)
{
m_Handle = NTKernel.CreateMutex(lpEventAttributes, bInitialOwner, lpName);
if (m_Handle == IntPtr.Zero)
{
uint err = NTKernel.GetLastError();
throw new Exception(String.Format("Create Event fail, error={0}",
err));
}
}
public Mutex(bool bInitialOwner, string lpName)
{
m_Handle = NTKernel.CreateMutex(null, bInitialOwner, lpName);
if (m_Handle == IntPtr.Zero)
{
uint err = NTKernel.GetLastError();
throw new Exception(String.Format("Create Event fail, error={0}",
err));
}
}
public bool WaitOne(uint dwMilliseconds)
{
WaitForState waitForState = (WaitForState)NTKernel.WaitForSingleObject((uint)m_Handle, dwMilliseconds);
if (waitForState == WaitForState.WAIT_OBJECT_0)
{
return true;
}
else if (waitForState == WaitForState.WAIT_TIMEOUT)
{
return false;
}
else
{
throw new System.Threading.AbandonedMutexException();
}
}
public bool WaitOne()
{
return WaitOne(NTKernel.INFINITE);
}
public void ReleaseMutex()
{
NTKernel.ReleaseMutex(m_Handle);
}
public void Close()
{
lock (this)
{
if (m_Handle != IntPtr.Zero)
{
if (NTKernel.CloseHandle((uint)m_Handle))
{
m_Handle = IntPtr.Zero;
}
}
}
}
~Mutex()
{
Dispose();
}
IDisposable Members
}
public class Event : IDisposable
{
IntPtr m_Handle;
public Event()
{
}
public Event(SecurityAttributes lpEventAttributes, bool bManualReset, bool bInitialState, string lpName)
{
m_Handle = NTKernel.CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName);
if (m_Handle == IntPtr.Zero)
{
uint err = NTKernel.GetLastError();
throw new Exception(String.Format("Create Event fail, error={0}",
err));
}
}
public bool Open(EventAccess dwDesiredAccess, bool bInheritHandle, string lpName)
{
m_Handle = NTKernel.OpenEvent((uint)dwDesiredAccess, bInheritHandle, lpName);
if (m_Handle == IntPtr.Zero)
{
return false;
}
else
{
return true;
}
}
public WaitForState WaitFor(uint dwMilliseconds)
{
return (WaitForState)NTKernel.WaitForSingleObject((uint)m_Handle, dwMilliseconds);
}
public WaitForState WaitFor()
{
return WaitFor(NTKernel.INFINITE);
}
public void SetEvent()
{
NTKernel.SetEvent(m_Handle);
}
public void Release()
{
NTKernel.ResetEvent(m_Handle);
}
public void Close()
{
lock (this)
{
if (m_Handle != IntPtr.Zero)
{
if (NTKernel.CloseHandle((uint)m_Handle))
{
m_Handle = IntPtr.Zero;
}
}
}
}
~Event()
{
Dispose();
}
IDisposable Members
}
}
客戶端呼叫
byte[] buf = new byte[10240];
Pipe.Client.PipeClient client = new Pipe.Client.PipeClient("test", 102400);
for (int i = 0; i < 10000; i++)
{
try
{
client.Send(buf);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
}
}
伺服器呼叫
static bool begin = true;
static System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
static int count = 0;
static object lockObj = new object();
static void ReceiveMessage(System.IO.MemoryStream m)
{
//Console.WriteLine(msg.Event);
lock (lockObj)
{
if (begin)
{
watch.Start();
begin = false;
}
count++;
if (count == 10000)
{
watch.Stop();
float len = m.Length;
Console.WriteLine(String.Format("{0} MB", (len * 10000 * 1000 / watch.ElapsedMilliseconds) / (1024 * 1024)));
Console.WriteLine(String.Format("{0} ms", watch.ElapsedMilliseconds));
}
}
}
static void ReceiveMessageError(Exception e)
{
Console.WriteLine(e.Message);
}
static void Main(string[] args)
{
Pipe.Server.PipeServer server = new Pipe.Server.PipeServer("Test", 102400);
server.OnReceiveMessage = ReceiveMessage;
server.OnReceiveMessageError = ReceiveMessageError;
server.Listen();
}
原始碼下載位置
相關文章
- Java的通過管道來實現執行緒通訊Java執行緒
- 管道流間的通訊
- Linux 的程式間通訊:管道Linux
- 什麼時候採用socket通訊,什麼時候採用http通訊HTTP
- 程序間通訊(1)-管道
- 匿名管道通訊實現
- 一個SystemC執行緒與SystemVerilog執行緒通訊的例子執行緒
- 利用管道Pipelines做程序間的通訊
- 通過串列埠進行通訊 :串列埠
- 使用SuperSocket的FixedHeaderReceiveFilter進行通訊HeaderFilter
- linux 程式間通訊之管道Linux
- Windows程式通訊之一看就懂的匿名管道通訊Windows
- 採用 OPA5 進行 SAP UI5 整合測試(Integration Test)的一個例子試讀版UI
- 一個簡單的netty通訊的例子Netty
- 系統程式設計——管道通訊程式設計
- Linux程式間通訊②:有名管道FIFOLinux
- linux程式間通訊--管道(PIPE & FIFO)Linux
- 併發技術3:管道通訊
- React的6種通訊方式(附帶例子)React
- C# 使用SuperSocket的FixedHeaderReceiveFilter進行通訊C#HeaderFilter
- 溫故之.NET程式間通訊——管道
- Linux 下的程式間通訊:使用管道和訊息佇列Linux佇列
- 簡單的Java實現Netty進行通訊JavaNetty
- 一段最簡單的使用socket.io進行伺服器和客戶端通訊的例子程式碼伺服器客戶端
- 利用windows api實現程式通訊(命名管道)WindowsAPI
- 20.2、python程式間通訊——佇列和管道Python佇列
- C++使用libcurl進行http通訊C++HTTP
- 使用UDP如何進行網路通訊UDP
- 如何使用Java串列埠進行資料通訊及應用案例Java串列埠
- C++ 用libcurl庫進行http通訊網路程式設計C++HTTP程式設計
- vue websocket nodeJS 進行實時通訊踩到的坑VueWebNodeJS
- 樂訊通雲通訊:物聯網路卡在健康行業的應用行業
- 3|程式間通訊--有名管道學習筆記筆記
- 利用橢圓曲線進行加密通訊加密
- $attrs 與 $listeners 進行「巢狀元件」通訊巢狀元件
- 在 Laravel 中使用 Workerman 進行 socket 通訊Laravel
- 使用Google Protocol Bufffers進行通訊(Ruby & C)GoProtocol
- 樂訊通雲通訊:物聯網路卡在各個行業的應用行業