作者:肖波
用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();



}
源码下载位置