posts - 32, comments - 603, trackbacks - 9, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

采用管道进行通讯的例子

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