程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> c#異步Socket Tcp服務器實現

c#異步Socket Tcp服務器實現

編輯:C#入門知識

c#異步Socket Tcp服務器實現


 

介紹

 

在c#中微軟已經提供了TcpListener和TcpClient來實現Tcp的通訊,這部分已經有人寫了比較好的異步服務器代碼 http://www.cnblogs.com/gaochundong/archive/2013/04/14/csharp_async_tcp_server.html 這位博主寫的博客質量真是高,我經常浏覽他的博客總是有很多讓我驚喜的地方,他使用的是TcpListener來實現的異步服務器的。

我的socket版本其實本質上和他的沒有區別,就只是改寫了一點點,所以在這裡貼一份代碼就是了,多的不解釋了

代碼

服務器核心代碼 AsyncServer.cs
/// 
    /// 異步SOCKET 服務器
    /// 
    public class AsyncServer : IDisposable
    {

        #region Fields
        /// 
        /// 服務器程序允許的最大客戶端連接數
        /// 
        private int _maxClient;

        /// 
        /// 當前的連接的客戶端數
        /// 
        private int _clientCount;

        /// 
        /// 服務器使用的異步socket
        /// 
        private Socket _serverSock;

        /// 
        /// 客戶端會話列表
        /// 
        private List _clients;

        private bool disposed = false;

        #endregion


        #region Properties

        /// 
        /// 服務器是否正在運行
        /// 
        public bool IsRunning { get; private set; }
        /// 
        /// 監聽的IP地址
        /// 
        public IPAddress Address { get; private set; }
        /// 
        /// 監聽的端口
        /// 
        public int Port { get; private set; }
        /// 
        /// 通信使用的編碼
        /// 
        public Encoding Encoding { get; set; }
        

        #endregion

        #region Ctors

        /// 
        /// 異步Socket TCP服務器
        /// 
        ///監聽的端口
        public AsyncServer(int listenPort)
            : this(IPAddress.Any, listenPort,1024)
        {
        }

        /// 
        /// 異步Socket TCP服務器
        /// 
        ///監聽的終結點
        public AsyncServer(IPEndPoint localEP)
            : this(localEP.Address, localEP.Port,1024)
        {
        }

        /// 
        /// 異步Socket TCP服務器
        /// 
        ///監聽的IP地址
        ///監聽的端口
        ///最大客戶端數量
        public AsyncServer(IPAddress localIPAddress, int listenPort,int maxClient)
        {
            this.Address = localIPAddress;
            this.Port = listenPort;
            this.Encoding = Encoding.Default;

            _maxClient = maxClient;
            _clients = new List();
            _serverSock = new Socket(localIPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        }

        #endregion


        #region Server

        /// 
        /// 啟動服務器
        /// 
        /// 異步TCP服務器
        public AsyncServer Start()
        {
            if (!IsRunning)
            {
                IsRunning = true;
                _serverSock.Bind(new IPEndPoint(this.Address, this.Port));
                _serverSock.Listen(1024);
                _serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
            }
            return this;
        }

        /// 
        /// 啟動服務器
        /// 
        ///
        /// 服務器所允許的掛起連接序列的最大長度
        /// 
        /// 異步TCP服務器
        public AsyncServer Start(int backlog)
        {
            if (!IsRunning)
            {
                IsRunning = true;
                _serverSock.Bind(new IPEndPoint(this.Address, this.Port));
                _serverSock.Listen(backlog);
                _serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
            }
            return this;
        }

        /// 
        /// 停止服務器
        /// 
        /// 異步TCP服務器
        public AsyncServer Stop()
        {
            if (IsRunning)
            {
                IsRunning = false;
                _serverSock.Close();
                //TODO 關閉對所有客戶端的連接

            }
            return this;
        }

        #endregion

        #region Receive
        /// 
        /// 處理客戶端連接
        /// 
        ///
        private void HandleAcceptConnected(IAsyncResult ar)
        {
            if (IsRunning)
            {
                Socket server = (Socket)ar.AsyncState;
                Socket client = server.EndAccept(ar);
                
                //檢查是否達到最大的允許的客戶端數目
                if (_clientCount == _maxClient)
                {
                    //TODO 觸發事件
                    RaiseServerException(null);
                }
                else
                {
                    Session session = new Session(client);
                    lock (_clients)
                    {
                        _clients.Add(session);
                        _clientCount++;
                        RaiseClientConnected(session); //觸發客戶端連接事件
                    }
                    session.RecvDataBuffer = new byte[client.ReceiveBufferSize];
                    //開始接受來自該客戶端的數據
                    client.BeginReceive(session.RecvDataBuffer, 0, session.RecvDataBuffer.Length, SocketFlags.None,
                     new AsyncCallback(HandleDataReceived), session);
                }
                //接受下一個請求
                server.BeginAccept(new AsyncCallback(HandleAcceptConnected), ar.AsyncState);
            }
        }
        /// 
        /// 處理客戶端數據
        /// 
        ///
        private void HandleDataReceived(IAsyncResult ar)
        {
            if (IsRunning)
            {
                Session session = (Session)ar.AsyncState;
                Socket client = session.ClientSocket;
                try
                {
                    //如果兩次開始了異步的接收,所以當客戶端退出的時候
                    //會兩次執行EndReceive
                    int recv = client.EndReceive(ar);
                    if (recv == 0)
                    {
                        //TODO 觸發事件 (關閉客戶端)
                        CloseSession(session);
                        RaiseNetError(session);
                        return;
                    }
                    //TODO 處理已經讀取的數據 ps:數據在session的RecvDataBuffer中
                    RaiseDataReceived(session);
                    //TODO 觸發數據接收事件
                }
                catch (SocketException ex)
                {
                    //TODO 異常處理
                    RaiseNetError(session);
                }
                finally
                {
                    //繼續接收來自來客戶端的數據
                    client.BeginReceive(session.RecvDataBuffer, 0, session.RecvDataBuffer.Length, SocketFlags.None,
                     new AsyncCallback(HandleDataReceived), session);
                }
            }
        }
        #endregion

        #region Send
        /// 
        /// 發送數據
        /// 
        ///接收數據的客戶端會話
        ///數據報文
        public void Send(Session session, byte[] data)
        {
            Send(session.ClientSocket,data);
        }

        /// 
        /// 異步發送數據至指定的客戶端
        /// 
        ///客戶端
        ///報文
        public void Send(Socket client, byte[] data)
        {
            if (!IsRunning)
                throw new InvalidProgramException(This TCP Scoket server has not been started.);

            if (client == null)
                throw new ArgumentNullException(client);

            if (data == null)
                throw new ArgumentNullException(data);
            client.BeginSend(data, 0, data.Length, SocketFlags.None,
             new AsyncCallback(SendDataEnd), client);
        }

        /// 
        /// 發送數據完成處理函數
        /// 
        ///目標客戶端Socket
        private void SendDataEnd(IAsyncResult ar)
        {
            ((Socket)ar.AsyncState).EndSend(ar);
        }
        #endregion

        #region Events
        /// 
        /// 接收到數據事件
        /// 
        public event EventHandler DataReceived;

        private void RaiseDataReceived(Session session)
        {
            if (DataReceived != null)
            {
                DataReceived(this, new AsyncEventArgs(session));
            }
        }

        /// 
        /// 與客戶端的連接已建立事件
        /// 
        public event EventHandler ClientConnected;
        /// 
        /// 與客戶端的連接已斷開事件
        /// 
        public event EventHandler ClientDisconnected;

        /// 
        /// 觸發客戶端連接事件
        /// 
        ///
        private void RaiseClientConnected(Session session)
        {
            if (ClientConnected != null)
            {
                ClientConnected(this, new AsyncEventArgs(session));
            }
        }
        /// 
        /// 觸發客戶端連接斷開事件
        /// 
        ///
        private void RaiseClientDisconnected(Socket client)
        {
            if (ClientDisconnected != null)
            {
                ClientDisconnected(this, new AsyncEventArgs(連接斷開));
            }
        }
        /// 
        /// 網絡錯誤事件
        /// 
        public event EventHandler NetError;
        /// 
        /// 觸發網絡錯誤事件
        /// 
        ///
        private void RaiseNetError(Session session)
        {
            if (NetError != null)
            {
                NetError(this, new AsyncEventArgs(session));
            }
        }

        /// 
        /// 異常事件
        /// 
        public event EventHandler ServerException;
        /// 
        /// 觸發異常事件
        /// 
        ///
        private void RaiseServerException(Session session)
        {
            if (ServerException != null)
            {
                ServerException(this, new AsyncEventArgs(session));
            }
        }
        #endregion


        #region Close
        /// 
        /// 關閉一個與客戶端之間的會話
        /// 
        ///需要關閉的客戶端會話對象
        public void CloseSession(Session session)
        {
            if (session != null)
            {
                session.Datagram = null;
                session.RecvDataBuffer = null;

                _clients.Remove(session);
                _clientCount--;
                //TODO 觸發關閉事件
                session.Close();
            }
        }
        /// 
        /// 關閉所有的客戶端會話,與所有的客戶端連接會斷開
        /// 
        public void CloseAllClient()
        {
            foreach (Session client in _clients)
            {
                CloseSession(client);
            }
            _clientCount = 0;
            _clients.Clear();
        }

        /// 
        /// Performs application-defined tasks associated with freeing, 
        /// releasing, or resetting unmanaged resources.
        /// 
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// 
        /// Releases unmanaged and - optionally - managed resources
        /// 
        ///true to release 
        /// both managed and unmanaged resources; false 
        /// to release only unmanaged resources.
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    try
                    {
                        Stop();
                        if (_serverSock != null)
                        {
                            _serverSock = null;
                        }
                    }
                    catch (SocketException ex)
                    {
                        //TODO
                        RaiseServerException(null);
                    }
                }
                disposed = true;
            }
        }
        #endregion
    }

其中使用了一個Session類,來封裝對客戶端的連接 Session,cs
/// 
    /// 客戶端與服務器之間的會話類
    /// 
    public class Session
    {
        #region 字段
        /// 
        /// 接收數據緩沖區
        /// 
        private byte[] _recvBuffer;

        /// 
        /// 客戶端發送到服務器的報文
        /// 注意:在有些情況下報文可能只是報文的片斷而不完整
        /// 
        private string _datagram;

        /// 
        /// 客戶端的Socket
        /// 
        private Socket _clientSock;

        #endregion

        #region 屬性

        /// 
        /// 接收數據緩沖區 
        /// 
        public byte[] RecvDataBuffer
        {
            get
            {
                return _recvBuffer;
            }
            set
            {
                _recvBuffer = value;
            }
        }

        /// 
        /// 存取會話的報文
        /// 
        public string Datagram
        {
            get
            {
                return _datagram;
            }
            set
            {
                _datagram = value;
            }
        }

        /// 
        /// 獲得與客戶端會話關聯的Socket對象
        /// 
        public Socket ClientSocket
        {
            get
            {
                return _clientSock;

            }
        }


        #endregion

        /// 
        /// 構造函數
        /// 
        ///會話使用的Socket連接
        public Session(Socket cliSock)
        {

            _clientSock = cliSock;
        }
        /// 
        /// 關閉會話
        /// 
        public void Close()
        {

            //關閉數據的接受和發送
            _clientSock.Shutdown(SocketShutdown.Both);

            //清理資源
            _clientSock.Close();
        }
    }

事件類
class AsyncEventArgs : EventArgs
    {
        /// 
        /// 提示信息
        /// 
        public string _msg;

        public Session _sessions;

        /// 
        /// 是否已經處理過了
        /// 
        public bool IsHandled { get; set; }

        public AsyncEventArgs(string msg)
        {
            this._msg = msg;
            IsHandled = false;
        }
        public AsyncEventArgs(Session session)
        {
            this._sessions = session;
            IsHandled = false;
        }
        public AsyncEventArgs(string msg, Session session)
        {
            this._msg = msg;
            this._sessions = session;
            IsHandled = false;
        }
    }

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved