采用管道进行通讯的例子

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


        }


源码下载位置

原文地址:https://www.cnblogs.com/xumaojun/p/8544099.html