|
|
Posted on 2008-06-12 15:40 eaglet 阅读(2025) 评论(21) 编辑 收藏 所属分类: .NET 、 操作系统
采用管道进行通讯的例子
作者:肖波
用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;
&nb |