eaglet

本博专注于基于微软技术的搜索相关技术
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

采用管道进行通讯的例子

Posted on 2008-06-12 15:40  eaglet  阅读(3376)  评论(21编辑  收藏  举报

采用管道进行通讯的例子

作者:肖波
    用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,
                    
0new SecurityAttributes(), (uint)CreateMode.OPEN_EXISTING, 00);

                
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();


        }

源码下载位置