一个server基类

发表于:2007-06-30来源:作者:点击数: 标签:
常用的 网络 server如http/ftp/pop3/smtp等基本上的工作原理都差不多,监听一个端口,等待客户端的Socket连接,然后同客户端通讯,完毕后关闭连接。如果要实现的比较完善,那就需要多线程,并且需要管理这些线程。下面给出一个server抽象类,利用一个看护线程
   常用的网络server如http/ftp/pop3/smtp等基本上的工作原理都差不多,监听一个端口,等待客户端的Socket连接,然后同客户端通讯,完毕后关闭连接。如果要实现的比较完善,那就需要多线程,并且需要管理这些线程。下面给出一个server抽象类,利用一个看护线程来管理连接线程,如果要写一个server那只需要继承这个类,并实现其抽象方法就可以了。

using System;
using System.Threading ;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections ;
using System.Text ;
using System.Diagnostics ;


namespace Bigeagle.Net.Server
{
    /// <summary>
    /// <br>server类</br>
    /// <br>Author: bigeagle@163.net</br>
    /// <br>Date :  2002/02/04</br>
    /// <br>History: 2002/02/04 finished</br>
    /// <br>Todo: 现在的类结构不尽合理,将来考虑使用delgates以便同winform绑定。</br>
    /// </summary>
    /// <remarks>
    /// <br>抽象类,用于一些常见的网络server的基类,如http,ftp,mail等。</br>
    /// <br>主要功能是监听一个端口,然后利用线程池起规定数量的线程等待客户端连接
    /// ,同时有一个守护线程监视线程使用情况,如果所有线程都在工作,则起一个空闲线程
    /// 继续等待客户端的连接。
    /// </br>
    /// <br>子类继承后必须实现其OnCommunication()抽象方法来完成自己要做的工作。</br>
    /// </remarks>
    public abstract class Server
    {
        #region 常量

        /// <summary>
        /// 守护线程工作时间间隔
        /// </summary>
        /// <remarks>每隔多少毫秒守护线程工作一次</remarks>
        const int WATCHING_INTERVAL = 10000 ;
        #endregion

        #region 静态变量

        /// <summary>
        /// 目前起的线程数
        /// </summary>
        static int intThreadCount ;

        /// <summary>
        /// 正在工作的线程数
        /// </summary>
        static int intWorkThreadCount ;

        #endregion

        #region 成员变量定义

        /// <summary>
        /// 线程信号
        /// </summary>
        private AutoResetEvent myEvent ;

        private bool m_bIsInitOK ;
        
        /// <summary>
        /// server名
        /// </summary>
        protected string m_strServerName ;

        /// <summary>
        /// 退出标志
        /// </summary>
        protected bool m_bCanExit ;

        /// <summary>
        /// 监听端口号
        /// </summary>
        protected int m_intPort ;

        /// <summary>
        /// 端口监听
        /// </summary>
        protected  TcpListener m_objListener ;

        /// <summary>
        /// 守护线程
        /// </summary>
        protected Thread m_objWatchThread ;

        /// <summary>
        /// 最小监听线程数
        /// </summary>
        protected int m_intMinThreadsCount ;

        /// <summary>
        /// 最大监听线程数
        /// </summary>
        protected int m_intMaxThreadsCount ;

        /// <summary>
        /// 编码方式
        /// </summary>
        protected System.Text.Encoding m_objEncoding ;

        #endregion        

        #region 属性定义

        public string ServerName
        {
            get
            {
                return this.m_strServerName ;
            }
            set
            {
                this.m_strServerName = value ;
            }
        }//end property

        /// <summary>
        /// 存取端口的属性
        /// </summary>
        public int Port
        {
            get
            {
                return this.m_intPort ;
            }
            set
            {
                this.m_intPort = value ;
            }
        }//end property

        /// <summary>
        /// 存取最小工作线程数的属性
        /// </summary>
        /// <remarks>server开始时启动的线程数,必须在1-999之间</remarks>
        public int MinThreadsCount
        {
            get
            {
                return this.m_intMinThreadsCount ;
            }
            set
            {
                if(value > 0 && value < 1000)
                {
                    this.m_intMinThreadsCount = value ;
                }
            }
        }//end property

        /// <summary>
        /// 存取最大工作线程数的属性
        /// </summary>
        /// <remarks>server最大能启动的线程数,必须在1-999之间,并且不能小于MinThreadsCounts</remarks>
        public int MaxThreadsCount
        {
            get
            {
                return this.m_intMaxThreadsCount ;
            }
            set
            {
                if(value > 0 && value < 1000)
                {
                    this.m_intMaxThreadsCount = value ;
                }
            }
        }//end property

        /// <summary>
        /// server默认编码方式
        /// </summary>
        public System.Text.Encoding Encoding
        {
            get
            {
                return this.m_objEncoding ;
            }
            set
            {
                this.m_objEncoding = value ;
            }
        }//end property
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        public Server()
        {
            this.m_strServerName        = "Bigelage General Server" ;
            this.m_bCanExit                = false ;
            this.m_intPort                = 0 ;
            this.m_objWatchThread        = new Thread(new ThreadStart(OnWatch)) ;
            this.m_objEncoding            = System.Text.Encoding.Default ;
            this.m_intMaxThreadsCount    = 10 ;
            this.m_intMinThreadsCount    = 1 ;
            this.myEvent                = new AutoResetEvent(false) ;
            this.m_bIsInitOK            = false ;
        }//end method

        /// <summary>
        /// 重载构造函数
        /// </summary>
        /// <param name="a_strServerName">server名</param>
        /// <param name="a_intPort">监听端口号</param>
        public Server(string a_strServerName , int a_intPort)
        {
            this.m_strServerName        = a_strServerName ;
            this.m_bCanExit                = false ;
            this.m_intPort                = a_intPort ;
            this.m_objWatchThread        = new Thread(new ThreadStart(OnWatch)) ;
            this.m_objEncoding            = System.Text.Encoding.Default ;
            this.m_intMaxThreadsCount    = 10 ;
            this.m_intMinThreadsCount    = 1 ;
            this.myEvent                = new AutoResetEvent(false) ;
            this.m_bIsInitOK            = false ;
        }//end method

        /// <summary>
        /// 析构函数
        /// </summary>
        ~Server()
        {
            try
            {
                if(this.m_objWatchThread.ThreadState == System.Threading.ThreadState.Running)
                {
                    this.m_objWatchThread.Interrupt() ;
                    this.m_objWatchThread = null ;
                }

                this.m_objListener.Stop() ;
                this.m_objListener = null ;
            }
            catch(Exception e)
            {
#if DEBUG
                Console.WriteLine("结束错误:{0}" , e.ToString()) ;
#endif//DEBUG
            }

        }


        #endregion

        #region 私有函数
        /// <summary>
        /// 守护线程工作函数
        /// </summary>
        private void OnWatch()
        {
#if DEBUG
            Console.WriteLine("watching thread now begin...") ;
#endif//DEBUG
            while(!this.m_bCanExit)
            {
#if DEBUG
                Console.WriteLine("now {0} threads is started , now {1} Thread is working"
                    , intThreadCount , intWorkThreadCount) ;
#endif//DEBUG
                ///如果所有线程都在工作,起一个空闲线程来监听
                if(this.m_bIsInitOK)
                {
                    if(intWorkThreadCount > 0
                        && intWorkThreadCount >= intThreadCount
                        && intThreadCount < this.m_intMaxThreadsCount)
                    {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(StartListen) , this.myEvent) ;
                    }
                }
                else
                {
#if DEBUG
                    Console.WriteLine("Server is initialize now ...") ;
#endif//DEBUG
                }

                Thread.Sleep(WATCHING_INTERVAL) ;            
            }
        }//end method
        #endregion

        #region 保护函数
        protected void Initialize()
        {
            this.m_objWatchThread.Start() ;
            this.m_objWatchThread.IsBackground = true ;
            //this.m_objWatchThread.Join() ;

            Console.Write("\r\n{0} is Initializing...." , this.m_strServerName) ;

#if DEBUG
            Debug.Assert(this.m_intPort != 0 , "未指定端口!") ;
#endif//DEBUG

            //绑定监听端口
            this.m_objListener = new TcpListener(this.m_intPort) ;
            this.m_bIsInitOK = true ;

        }//end method

        /// <summary>
        /// 监听线程工作函数
        /// </summary>
        /// <param name="state">AutoResetEvent对象</param>
        protected void StartListen(object state)
        {
#if DEBUG
            Console.WriteLine("thread{0} is waiting..." , Thread.CurrentThread.GetHashCode()) ;
#endif//DEBUG

            //线程计数加一
            Interlocked.Increment(ref intThreadCount) ;


            try
            {
                while(!this.m_bCanExit)
                {
                    //等待接收一个新连接
                    Socket mySocket = this.m_objListener.Aclearcase/" target="_blank" >cceptSocket() ;
#if DEBUG
                    Console.WriteLine("thread {0} begin working..." , Thread.CurrentThread.GetHashCode()) ;
#endif//DEBUG
                    if(mySocket.Connected)
                    {
                        //工作线程计数加一
                        Interlocked.Increment(ref intWorkThreadCount) ;

                        //同客户端交互
                        DoCommunication(mySocket) ;

                        //完毕后工作线程计数减一
                        Interlocked.Decrement(ref intWorkThreadCount) ;
                        mySocket.Close() ;
#if DEBUG
                        Console.WriteLine("thread {0} finished work" , Thread.CurrentThread.GetHashCode()) ;
#endif//DEBUG
                        if(intWorkThreadCount < intThreadCount - 1
                            && intThreadCount > this.m_intMinThreadsCount)
                        {
#if DEBUG
                            Console.WriteLine("Too many not working thread , thread {0} will exit."
                                , Thread.CurrentThread.GetHashCode()) ;
#endif//DEBUG
                            Interlocked.Decrement(ref intThreadCount) ;
                            return ;
                        }
                
                    }
                }//end while
            }
            catch(SocketException se)
            {
#if DEBUG
                Console.WriteLine("出现网络错误,工作线程关闭。错误{0}" , se.ToString()) ;
#endif//DEBUG
                Interlocked.Decrement(ref intThreadCount) ;
                Interlocked.Decrement(ref intWorkThreadCount) ;

            }
            catch(Exception e)
            {
#if DEBUG
                Console.WriteLine("出现错误:{0}" , e.Message) ;
#endif//DEBUG
                Interlocked.Decrement(ref intThreadCount) ;
            
            }

//            if(intWorkThreadCount == 0)
//            {
//                ((AutoResetEvent)state).Set() ;
//            }
        }//end method

        /// <summary>
        /// 抽象方法,同客户端通讯
        /// </summary>
        /// <param name="a_objSocket">当前套接字</param>
        protected abstract void DoCommunication(Socket a_objSocket) ;

        #endregion

        #region 公共方法
        /// <summary>
        /// 运行
        /// </summary>
        public void Run()
        {
            Initialize() ;
            Console.WriteLine("{0} is running..." , this.m_strServerName) ;

            try
            {
                //开始监听端口
                this.m_objListener.Start() ;
                
                //起最小工作线程数量的端口监听线程
                for(int i = 0 ; i < this.m_intMinThreadsCount ; i ++)
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(StartListen) , myEvent) ;
                }

                myEvent.WaitOne() ;
#if DEBUG
                Console.WriteLine("all thread exit") ;
#endif

            }
            catch (SocketException socketError)
            {
                if (socketError.ErrorCode == 10048)
                {
                    Console.WriteLine("Connection to this port failed. "
                        + " There is another server is listening on this port.");
                }
                else
                {
                    Console.WriteLine("A Socket error occours:{0}" ,socketError.Message) ;
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("An error occours:{0}" , e.Message) ;
            }
            

        }//end method

        public void Stop()
        {
            Console.WriteLine("{0} try to stop . " , this.m_strServerName) ;

            //发出退出信号
            this.m_bCanExit = true ;

            //等待所有工作的线程结束任务,500毫秒检查一次
            while(intWorkThreadCount != 0)
            {
                Thread.Sleep(500) ;
            }

            //发出线程结束信号,通知主程序可以退出
            this.myEvent.Set() ;

        }

        #endregion

    }//end class
}//end namespace

原文转自:http://www.ltesting.net