一个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.Inter
rupt() ;
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
De
bug.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.A
clearcase/" 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