本文介紹
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)!