现在的位置: 首页 > 综合 > 正文

Socket开发探秘–基类及公共类的定义

2013年05月24日 ⁄ 综合 ⁄ 共 11159字 ⁄ 字号 评论关闭

Socket开发是属于通信底层的开发,.NET也提供了非常丰富的类来实现Socket的开发工作,本篇不是介绍这些基础类的操作,而是从一个大的架构方面阐述Socket的快速开发工作,本篇以TCP模式进行程序的开发介绍,以期达到抛砖引玉的目的。

要掌握或者了解Socket开发,必须了解下面所述的场景及知识。

1、TCP客户端,连接服务器端,进行数据通信

2、TCP服务器端,负责侦听客户端连接

3、连接客户端的管理,如登陆,注销等,使用独立线程处理

4、数据接收管理,负责数据的接受,并处理队列的分发,使用独立线程处理,简单处理后叫给“数据处理线程”

5、数据处理线程,对特定的数据,采用独立的线程进行数据处理

6、数据的封包和解包,按照一定的协议进行数据的封装和解包

 

针对以上内容,可以封装以下功能的操作类作为共用基类:

1、BaseSocketClient,客户端基类

2、BaseSocketServer,TCP服务器管理基类

3、BaseClientManager,连接客户端管理类

4、BaseReceiver,数据接收处理类

5、ThreadHandler,数据独立线程处理类

6、PreData、DataTypeKey、Sign分别是定义数据的基础格式、协议标识、分隔符号等,另外我们定义需要发送的实体类信息,发送和接收通过实体类进行数据转换和解析。

 

以上类是基类,不能直接使用,在服务器端和客户端都要继承相应的类来完成所需要的工作。

BaseSocketClient只要负责客户端的链接、断开、发送、接收等操作,大致的定义如下:

代码

    public class BaseSocketClient
    {       
        
public BaseSocketClient()
        {
            _Name 
= this.GetType().Name;
        }

        public BaseSocketClient(Socket socket) : this()
        {
            _socket 
= socket;
            IPEndPoint ipAndPort 
= (IPEndPoint)socket.RemoteEndPoint;
            _IP 
= ipAndPort.Address.ToString();
            _port 
= ipAndPort.Port;
        }

        /// <summary>
        
/// 断开连接
        
/// </summary>
        public virtual void DisConnect()
        {
            .........
        }

        /// <summary>
        
/// 主动连接
        
/// </summary>
        public virtual void Connect(string ip, int port)
        {
            ........
        }
        
        
/// <summary>
        
/// 开始异步接收
        
/// </summary>
        public void BeginReceive()
        {
            .........
        }
        
         
/// <summary>
         
/// 开始同步接收
         
/// </summary>               
         public void StartReceive()
         {
              .........
         }
         
        
/// <summary>
        
///异步发送
        
/// </summary>
        public void BeginSend(SendStateObject sendState)
        {
            ........
        }
        
        
/// <summary>
        
/// 同步发送。直接返回成功失败状态
        
/// </summary>
        public bool SendTo(string data)
        {
            .........
        }
        
/// <summary>
        
/// 主动检查连接
        
/// </summary>
        public virtual void CheckConnect()
        {
            .............
        }
        
        
protected virtual void OnRead(PreData data)
        {
        }
    }

  

2、BaseSocketServer,TCP服务器管理基类

该类负责在独立的线程中侦听指定的端口,如果有客户端连接进来,则进行相应的处理,重载处理函数可以实现独立的处理。大致的定义如下。

代码

    public class BaseSocketServer
    {
        
public BaseSocketServer()
        {
            
this._SocketName = this.GetType().Name;
        }

        /// <summary>
        
/// 启动监听线程
        
/// </summary>
        public void StartListen(string ip, int port)
        {
            _IP 
= ip;
            _port 
= port;
            
if (_listenThread == null)
            {
                _listenThread 
= new Thread(Listen);
                _listenThread.IsBackground 
= true;
                _listenThread.Start();
            }
        }

        /// <summary>
        
/// 检查监听线程
        
/// </summary>
        public void CheckListen()
        {
            
if (_listenThread == null || (!_listenThread.IsAlive))
            {
                _listenThread 
= new Thread(Listen);
                _listenThread.IsBackground 
= true;
                _listenThread.Start();
            }
        }

        /// <summary>
        
/// 监听线程
        
/// </summary>
        protected virtual void Listen()
        {
            IPEndPoint ipAndPort 
= new IPEndPoint(IPAddress.Parse(IP), Port);
            TcpListener tcpListener 
= new TcpListener(ipAndPort);
            tcpListener.Start(
50);//配置

            
while (true)
            {
                Socket socket 
= tcpListener.AcceptSocket();
                AcceptClient(socket);
             }
        }

        /// <summary>
        
/// 接收一个Client
        
/// </summary>
        protected virtual void AcceptClient(Socket socket)
        {
        }

  

3、BaseClientManager,连接客户端管理类

由于考虑性能的影响,客户端对象的管理交给一个独立的线程进行处理,一则处理思路清晰,二则充分利用线程的性能。该类主要负责客户端登录超时处理,连接上来的客户端维护,经过登陆验证的客户端维护,客户端登陆验证接口,客户端发送数据处理等功能。

 

代码

    public class BaseClientManager<T> where T : BaseSocketClient
    {
        
#region 登陆管理

        protected string _Name = "BaseClientManager";
        
private int _SessionId = 0;
        
private object _LockSession = new object();

        private System.Threading.Timer _CheckInvalidClientTimer = null;// 检查客户端连接timer
        private System.Threading.Timer _SendTimer = null;// 发送数据调用timer

        
/// <summary>
        
/// 已经注册的客户端 关键字userid
        
/// </summary>
        protected SortedList<string, T> _loginClientList = new SortedList<string, T>();
        
/// <summary>
        
/// 连上来的客户端 未注册 关键字Session
        
/// </summary>
        protected SortedList<string, T> _tempClientList = new SortedList<string, T>();
        
        
/// <summary>
        
/// 构造函数
        
/// </summary>
        public BaseClientManager()
        {
            
this._Name = this.GetType().Name;
        }

        /// <summary>
        
/// 已经注册的客户端 关键字userid
        
/// </summary>
        public SortedList<string, T> LoginClientList
        {
            
get { return _loginClientList; }
            
set { _loginClientList = value; }
        }

        /// <summary>
        
/// 增加一个连上来(未注册)的客户端
        
/// </summary>
        
/// <param name="client"></param>
        public void AddClient(T client)
        {
            ......
        }

        /// <summary>
        
/// 增加一个已登录的客户端
        
/// </summary>
        public void AddLoginClient(T client)
        {
            ......
        }

        /// <summary>
        
/// 当客户端登陆,加入列表后的操作
        
/// </summary>
        
/// <param name="client"></param>
        protected virtual void OnAfterClientSignIn(T client)
        {
        }

        /// <summary>
        
/// 验证登录
        
/// </summary>
        public virtual bool CheckClientLogin(string userId, string psw, ref string memo)
        {
            
return false;
        }

        /// <summary>
        
/// 电召客户端登出
        
/// </summary>
        
/// <param name="userId"></param>
        public void ClientLogout(string userId)
        {
            
if (_loginClientList.ContainsKey(userId))
            {
                RadioCallClientLogout(_loginClientList[userId]);
            }
        }

        /// <summary>
        
/// 电召客户端登出
        
/// </summary>
        
/// <param name="client"></param>
        private void RadioCallClientLogout(T client)
        {
            client.DisConnect();
        }

        /// <summary>
        
/// 移除注册的客户端
        
/// </summary>
        
/// <param name="client"></param>
        private void RemoveLoginClient(T client)
        {
            ......
        }

        /// <summary>
        
/// 移除客户端后的操作
        
/// </summary>
        
/// <param name="client"></param>
        protected virtual void OnAfterClientLogout(T client)
        {
        }

        /// <summary>
        
/// 在连接的列表中移除客户端对象
        
/// </summary>
        
/// <param name="client"></param>
        public virtual void RemoveClient(T client)
        {
            RemoveLoginClient(client);
            RemoveTempClient(client);
        }
        
        
#endregion

        /// <summary>
        
/// 开始客户端连接处理
        
/// </summary>
        public void Start()
        {
            StartSendTimer();
            StartCheckInvalidClientTimer();
        }

        /// <summary>
        
/// 启动客户端发送数据线程
        
/// </summary>
        public void StartSendTimer()
        {
            ......
        }

        /// <summary>
        
/// 启动检查客户端连接timer
        
/// </summary>
        public void StartCheckInvalidClientTimer()
        {
            ......
        }

        /// <summary>
        
/// 检查客户端连接
        
/// </summary>
        
/// <param name="stateInfo"></param>
        private void CheckInvalidClient(Object stateInfo)
        {
            ......
        }

        public virtual void RemoveInvalidClient()
        {
            ......
        }

        /// <summary>
        
/// 增加一条客户端发送数据
        
/// </summary>
        public void AddSend(string userid, string send, bool isFirst)
        {
            ......
        }
    }

 

 

4、BaseReceiver,数据接收处理类

该基类是所有接受数据的处理类,负责维护数据的队列关系,并进一步进行处理。

代码

    public class BaseReceiver
    {
        
protected string _Name = "BaseReceiver";
        
protected Thread _PreDataHandlehread = null;// 处理数据线程
        protected Fifo<PreData> _preDataFifo = new Fifo<PreData>(50000);

        public BaseReceiver()
        {
            _Name 
= this.GetType().Name;
        }

        /// <summary>
        
/// 接收处理数据
        
/// </summary>
        public void AppendPreData(PreData data)
        {
            _preDataFifo.Append(data);
        }

        /// <summary>
        
/// 数据处理
        
/// </summary>
        protected virtual void PreDataHandle()
        {
            ......
        }

        /// <summary>
        
/// 数据处理
        
/// </summary>
        
/// <param name="data"></param>
        public virtual void PreDataHandle(PreData data)
        { 
        }

        /// <summary>
        
/// 开始数据处理线程
        
/// </summary>
        public virtual void Start()
        {
            
if (_PreDataHandlehread == null)
            {
                _PreDataHandlehread 
= new Thread(new ThreadStart(PreDataHandle));
                _PreDataHandlehread.IsBackground 
= true;
                _PreDataHandlehread.Start();
            }
        }
    }

 

 

5、ThreadHandler,数据独立线程处理类

对每个不同类型的数据(不同的协议类型),可以用独立的线程进行处理,这里封装了一个基类,用于进行数据独立线程的处理。

代码

    public class ThreadHandler<T>
    {
        Thread _Handlehread 
= null;// 处理数据线程
        private string _ThreadName = "";
        
private Fifo<T> _DataFifo = new Fifo<T>();

        /// <summary>
        
/// 接收处理数据
        
/// </summary>
        public virtual void AppendData(T data)
        {
            
if (data != null)
                _DataFifo.Append(data);
        }

        /// <summary>
        
/// 数据处理
        
/// </summary>
        protected virtual void DataThreadHandle()
        {
            
while (true)
            {
                    T data 
= _DataFifo.Pop();
                DataHandle(data);
            }
        }

        /// <summary>
        
/// 数据处理
        
/// </summary>
        
/// <param name="data"></param>
        public virtual void DataHandle(T data)
        {
        }

        /// <summary>
        
/// 检查数据处理线程
        
/// </summary>
        public virtual void Check()
        {
            ......
        }

        /// <summary>
        
/// 开始数据处理线程
        
/// </summary>
        public virtual void StartHandleThread()
        {
            ......
        }
    }

 

 

6、PreData、DataTypeKey、Sign

 PreData是定义了一个标准的协议数据格式,包含了协议关键字、协议内容、用户标识的内容,代码如下。

 

代码

    /// <summary>
    
/// 预处理的数据
    
/// </summary>
    public class PreData
    {
        
private string _key;
        
private string _content;
        
private string _userId;

        public PreData()
        { 
        }

        public PreData(string key,string data)
        {
            _key 
= key;
            _content 
= data;
        }

        /// <summary>
        
/// 协议关键字
        
/// </summary>
        public string Key
        {
            
get { return _key; }
            
set { _key = value; }
        }

        /// <summary>
        
/// 数据内容
        
/// </summary>
        public string Content
        {
            
get { return _content; }
            
set { _content = value; }
        }

        /// <summary>
        
/// 客户端过来为用户帐号,或者指定的名称
        
/// </summary>
        public string UserId
        {
            
get { return _userId; }
            
set { _userId = value; }
        }
    }

 

 

其中的DataTypeKey和Sign定义了一系列的协议头关键字和数据分隔符等信息。

抱歉!评论已关闭.