C#網路編程系列文章(三)之TcpListener實現非同步TCP伺服器

來源:互聯網
上載者:User

本文介紹

TcpListener 類提供一些簡單方法,用於在阻止同步模式下偵聽和接受傳入串連請求。 可使用 TcpClient 或 Socket 來串連 TcpListener。 可使用 IPEndPoint、本地 IP 位址及連接埠號碼或者僅使用連接埠號碼,來建立 TcpListener。 可以將本地 IP 位址指定為 Any,將本地連接埠號碼指定為 0(如果希望基礎服務提供者為您分配這些值)。 如果您選擇這樣做,可在串連通訊端後使用 LocalEndpoint 屬性來標識已指定的資訊。使用 Start 方法,可開始偵聽傳入的串連請求。 Start 將對傳入串連進行排隊,直至您調用 Stop 方法或它已經完成 MaxConnections 排隊為止。 可使用 AcceptSocket 或 AcceptTcpClient 從傳入串連請求隊列提取串連。 這兩種方法將阻止。 如果要避免阻止,可首先使用 Pending 方法來確定隊列中是否有可用的串連請求。

雖然TcpListener已經封裝的比較不錯了,我們於是就使用它在構造一個比較不錯的非同步TCP伺服器,這裡依然和前兩章一樣,給出伺服器中的代碼,代碼中注釋很詳細,我也會給出相關的封裝類。

TcpListener非同步TCP伺服器

伺服器代碼

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net.Sockets;using System.Net;namespace NetFrame.Net.TCP.Listener.Asynchronous{    /// <summary>    /// TcpListener實現非同步TCP伺服器    /// </summary>    public class AsyncTCPServer : IDisposable    {        #region Fields        /// <summary>        /// 伺服器程式允許的最大用戶端串連數        /// </summary>        private int _maxClient;        /// <summary>        /// 當前的串連的用戶端數        /// </summary>        private int _clientCount;        /// <summary>        /// 伺服器使用的非同步TcpListener        /// </summary>        private TcpListener _listener;        /// <summary>        /// 用戶端工作階段列表        /// </summary>        private List<Object> _clients;        private bool disposed = false;        #endregion        #region Properties        /// <summary>        /// 伺服器是否正在運行        /// </summary>        public bool IsRunning { get; private set; }        /// <summary>        /// 監聽的IP地址        /// </summary>        public IPAddress Address { get; private set; }        /// <summary>        /// 監聽的連接埠        /// </summary>        public int Port { get; private set; }        /// <summary>        /// 通訊使用的編碼        /// </summary>        public Encoding Encoding { get; set; }        #endregion        #region 建構函式        /// <summary>        /// 非同步TCP伺服器        /// </summary>        /// <param name="listenPort">監聽的連接埠</param>        public AsyncTCPServer(int listenPort)            : this(IPAddress.Any, listenPort)        {        }        /// <summary>        /// 非同步TCP伺服器        /// </summary>        /// <param name="localEP">監聽的終結點</param>        public AsyncTCPServer(IPEndPoint localEP)            : this(localEP.Address, localEP.Port)        {        }        /// <summary>        /// 非同步TCP伺服器        /// </summary>        /// <param name="localIPAddress">監聽的IP地址</param>        /// <param name="listenPort">監聽的連接埠</param>        public AsyncTCPServer(IPAddress localIPAddress, int listenPort)        {            Address = localIPAddress;            Port = listenPort;            this.Encoding = Encoding.Default;            _clients = new List<Object>();            _listener = new TcpListener(Address, Port);            _listener.AllowNatTraversal(true);        }        #endregion        #region Method        /// <summary>        /// 啟動伺服器        /// </summary>        public void Start()        {            if (!IsRunning)            {                IsRunning = true;                _listener.Start();                _listener.BeginAcceptTcpClient(                  new AsyncCallback(HandleTcpClientAccepted), _listener);            }        }        /// <summary>        /// 啟動伺服器        /// </summary>        /// <param name="backlog">        /// 伺服器所允許的掛起串連序列的最大長度        /// </param>        public void Start(int backlog)        {            if (!IsRunning)            {                IsRunning = true;                _listener.Start(backlog);                _listener.BeginAcceptTcpClient(                  new AsyncCallback(HandleTcpClientAccepted), _listener);            }        }        /// <summary>        /// 停止伺服器        /// </summary>        public void Stop()        {            if (IsRunning)            {                IsRunning = false;                _listener.Stop();                lock (_clients)                {                    //關閉所有用戶端串連                    CloseAllClient();                }            }        }        /// <summary>        /// 處理用戶端串連的函數        /// </summary>        /// <param name="ar"></param>        private void HandleTcpClientAccepted(IAsyncResult ar)        {            if (IsRunning)            {                //TcpListener tcpListener = (TcpListener)ar.AsyncState;                TcpClient client = _listener.EndAcceptTcpClient(ar);                byte[] buffer = new byte[client.ReceiveBufferSize];                TCPClientState state                  = new TCPClientState(client, buffer);                lock (_clients)                {                    _clients.Add(state);                    RaiseClientConnected(state);                }                NetworkStream stream = state.NetworkStream;                //開始非同步讀取資料                stream.BeginRead(state.Buffer, 0, state.Buffer.Length, HandleDataReceived, state);                _listener.BeginAcceptTcpClient(                  new AsyncCallback(HandleTcpClientAccepted), ar.AsyncState);            }        }        /// <summary>        /// 資料接受回呼函數        /// </summary>        /// <param name="ar"></param>        private void HandleDataReceived(IAsyncResult ar)        {            if (IsRunning)            {                TCPClientState state = (TCPClientState)ar.AsyncState;                NetworkStream stream = state.NetworkStream;                int recv = 0;                try                {                    recv = stream.EndRead(ar);                }                catch                {                    recv = 0;                }                if (recv == 0)                {                    // connection has been closed                    lock (_clients)                    {                        _clients.Remove(state);                        //觸發用戶端串連斷開事件                        RaiseClientDisconnected(state);                        return;                    }                }                // received byte and trigger event notification                byte[] buff = new byte[recv];                Buffer.BlockCopy(state.Buffer, 0, buff, 0, recv);                //觸發資料收到事件                RaiseDataReceived(state);                // continue listening for tcp datagram packets                stream.BeginRead(state.Buffer, 0, state.Buffer.Length, HandleDataReceived, state);            }        }        /// <summary>        /// 發送資料        /// </summary>        /// <param name="state">接收資料的用戶端工作階段</param>        /// <param name="data">資料報文</param>        public void Send(TCPClientState state, byte[] data)        {            RaisePrepareSend(state);            Send(state.TcpClient, data);        }        /// <summary>        /// 非同步發送資料至指定的用戶端        /// </summary>        /// <param name="client">用戶端</param>        /// <param name="data">報文</param>        public void Send(TcpClient 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.GetStream().BeginWrite(data, 0, data.Length, SendDataEnd, client);        }        /// <summary>        /// 發送資料完成處理函數        /// </summary>        /// <param name="ar">勘探端Socket</param>        private void SendDataEnd(IAsyncResult ar)        {            ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar);            RaiseCompletedSend(null);        }        #endregion        #region 事件        /// <summary>        /// 與用戶端的串連已建立事件        /// </summary>        public event EventHandler<AsyncEventArgs> ClientConnected;        /// <summary>        /// 與用戶端的串連已斷開事件        /// </summary>        public event EventHandler<AsyncEventArgs> ClientDisconnected;        /// <summary>        /// 觸發用戶端串連事件        /// </summary>        /// <param name="state"></param>        private void RaiseClientConnected(TCPClientState state)        {            if (ClientConnected != null)            {                ClientConnected(this, new AsyncEventArgs(state));            }        }        /// <summary>        /// 觸發用戶端串連斷開事件        /// </summary>        /// <param name="client"></param>        private void RaiseClientDisconnected(TCPClientState state)        {            if (ClientDisconnected != null)            {                ClientDisconnected(this, new AsyncEventArgs("串連斷開"));            }        }        /// <summary>        /// 接收到資料事件        /// </summary>        public event EventHandler<AsyncEventArgs> DataReceived;        private void RaiseDataReceived(TCPClientState state)        {            if (DataReceived != null)            {                DataReceived(this, new AsyncEventArgs(state));            }        }        /// <summary>        /// 發送資料前的事件        /// </summary>        public event EventHandler<AsyncEventArgs> PrepareSend;        /// <summary>        /// 觸發發送資料前的事件        /// </summary>        /// <param name="state"></param>        private void RaisePrepareSend(TCPClientState state)        {            if (PrepareSend != null)            {                PrepareSend(this, new AsyncEventArgs(state));            }        }        /// <summary>        /// 資料發送完畢事件        /// </summary>        public event EventHandler<AsyncEventArgs> CompletedSend;        /// <summary>        /// 觸發資料發送完畢的事件        /// </summary>        /// <param name="state"></param>        private void RaiseCompletedSend(TCPClientState state)        {            if (CompletedSend != null)            {                CompletedSend(this, new AsyncEventArgs(state));            }        }        /// <summary>        /// 網路錯誤事件        /// </summary>        public event EventHandler<AsyncEventArgs> NetError;        /// <summary>        /// 觸發網路錯誤事件        /// </summary>        /// <param name="state"></param>        private void RaiseNetError(TCPClientState state)        {            if (NetError != null)            {                NetError(this, new AsyncEventArgs(state));            }        }        /// <summary>        /// 例外狀況事件        /// </summary>        public event EventHandler<AsyncEventArgs> OtherException;        /// <summary>        /// 觸發例外狀況事件        /// </summary>        /// <param name="state"></param>        private void RaiseOtherException(TCPClientState state, string descrip)        {            if (OtherException != null)            {                OtherException(this, new AsyncEventArgs(descrip, state));            }        }        private void RaiseOtherException(TCPClientState state)        {            RaiseOtherException(state, "");        }        #endregion        #region Close        /// <summary>        /// 關閉一個與用戶端之間的會話        /// </summary>        /// <param name="state">需要關閉的用戶端工作階段對象</param>        public void Close(TCPClientState state)        {            if (state != null)            {                state.Close();                _clients.Remove(state);                _clientCount--;                //TODO 觸發關閉事件            }        }        /// <summary>        /// 關閉所有的用戶端工作階段,與所有的用戶端串連會斷開        /// </summary>        public void CloseAllClient()        {            foreach (TCPClientState client in _clients)            {                Close(client);            }            _clientCount = 0;            _clients.Clear();        }        #endregion        #region 釋放        /// <summary>        /// Performs application-defined tasks associated with freeing,         /// releasing, or resetting unmanaged resources.        /// </summary>        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }        /// <summary>        /// Releases unmanaged and - optionally - managed resources        /// </summary>        /// <param name="disposing"><c>true</c> to release         /// both managed and unmanaged resources; <c>false</c>         /// to release only unmanaged resources.</param>        protected virtual void Dispose(bool disposing)        {            if (!this.disposed)            {                if (disposing)                {                    try                    {                        Stop();                        if (_listener != null)                        {                            _listener = null;                        }                    }                    catch (SocketException)                    {                        //TODO                        RaiseOtherException(null);                    }                }                disposed = true;            }        }        #endregion    }}

用戶端處理封裝類

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net.Sockets;namespace NetFrame.Net.TCP.Listener.Asynchronous{    public class TCPClientState    {        /// <summary>        /// 與用戶端相關的TcpClient        /// </summary>        public TcpClient TcpClient { get; private set; }        /// <summary>        /// 擷取緩衝區        /// </summary>        public byte[] Buffer { get; private set; }        /// <summary>        /// 擷取網路流        /// </summary>        public NetworkStream NetworkStream        {            get { return TcpClient.GetStream(); }        }        public TCPClientState(TcpClient tcpClient, byte[] buffer)        {            if (tcpClient == null)                throw new ArgumentNullException("tcpClient");            if (buffer == null)                throw new ArgumentNullException("buffer");            this.TcpClient = tcpClient;            this.Buffer = buffer;        }        /// <summary>        /// 關閉        /// </summary>        public void Close()        {            //關閉資料的接受和發送            TcpClient.Close();            Buffer = null;        }    }}

伺服器事件參數類

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace NetFrame.Net.TCP.Listener.Asynchronous{    /// <summary>    /// 非同步TcpListener TCP伺服器事件參數類     /// </summary>    public class AsyncEventArgs:EventArgs    {         /// <summary>        /// 提示資訊        /// </summary>        public string _msg;        /// <summary>        /// 用戶端狀態封裝類        /// </summary>        public TCPClientState _state;        /// <summary>        /// 是否已經處理過了        /// </summary>        public bool IsHandled { get; set; }        public AsyncEventArgs(string msg)        {            this._msg = msg;            IsHandled = false;        }        public AsyncEventArgs(TCPClientState state)        {            this._state = state;            IsHandled = false;        }        public AsyncEventArgs(string msg, TCPClientState state)        {            this._msg = msg;            this._state = state;            IsHandled = false;        }    }}

以上就是C#網路編程系列文章(三)之TcpListener實現非同步TCP伺服器的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.