看了系列一 我們開啟了對socket tcp的監聽狀態,那么這一章我們來講解怎么創建socket的通信代碼
我新建一個類 TSocketBase
public abstract class TSocketBase { //封裝socket internal Socket _Socket; //回調 private AsyncCallback aCallback; //接受數據的緩沖區 private byte[] Buffers; //標識是否已經釋放 private volatile bool IsDispose; //10K的緩沖區空間 private int BufferSize = 10*1024; //收取消息狀態碼 private SocketError ReceiveError; //發送消息的狀態碼 private SocketError SenderError; //每一次接受到的字節數 private int ReceiveSize = 0; //接受空消息次數 private byte ZeroCount = 0; public abstract void Receive(byte[] rbuff); public void SetSocket() { this.aCallback = new AsyncCallback(this.ReceiveCallback); this.IsDispose = false; this._Socket.ReceiveBufferSize = this.BufferSize; this._Socket.SendBufferSize = this.BufferSize; this.Buffers = new byte[this.BufferSize]; } /// <summary> /// 關閉並釋放資源 /// </summary> /// <param name="msg"></param> public void Close(string msg) { if (!this.IsDispose) { this.IsDispose = true; try { try { this._Socket.Close(); } catch { } IDisposable disposable = this._Socket; if (disposable != null) { disposable.Dispose(); } this.Buffers = null; GC.SuppressFinalize(this); } catch (Exception) { } } } /// <summary> /// 遞歸接收消息方法 /// </summary> internal void ReceiveAsync() { try { if (!this.IsDispose && this._Socket.Connected) { this._Socket.BeginReceive(this.Buffers, 0, this.BufferSize, SocketFlags.None, out SenderError, this.aCallback, this); CheckSocketError(ReceiveError); } } catch (System.Net.Sockets.SocketException) { this.Close("鏈接已經被關閉"); } catch (System.ObjectDisposedException) { this.Close("鏈接已經被關閉"); } } /// <summary> /// 接收消息回調函數 /// </summary> /// <param name="iar"></param> private void ReceiveCallback(IAsyncResult iar) { if (!this.IsDispose) { try { //接受消息 ReceiveSize = _Socket.EndReceive(iar, out ReceiveError); //檢查狀態碼 if (!CheckSocketError(ReceiveError) && SocketError.Success == ReceiveError) { //判斷接受的字節數 if (ReceiveSize > 0) { byte[] rbuff = new byte[ReceiveSize]; Array.Copy(this.Buffers, rbuff, ReceiveSize); this.Receive(rbuff); //重置連續收到空字節數 ZeroCount = 0; //繼續開始異步接受消息 ReceiveAsync(); } else { ZeroCount++; if (ZeroCount == 5) { this.Close("錯誤鏈接"); } } } } catch (System.Net.Sockets.SocketException) { this.Close("鏈接已經被關閉"); } catch (System.ObjectDisposedException) { this.Close("鏈接已經被關閉"); } } } /// <summary> /// 錯誤判斷 /// </summary> /// <param name="socketError"></param> /// <returns></returns> private bool CheckSocketError(SocketError socketError) { switch ((socketError)) { case SocketError.SocketError: case SocketError.VersionNotSupported: case SocketError.TryAgain: case SocketError.ProtocolFamilyNotSupported: case SocketError.ConnectionAborted: case SocketError.ConnectionRefused: case SocketError.ConnectionReset: case SocketError.Disconnecting: case SocketError.HostDown: case SocketError.HostNotFound: case SocketError.HostUnreachable: case SocketError.NetworkDown: case SocketError.NetworkReset: case SocketError.NetworkUnreachable: case SocketError.NoData: case SocketError.OperationAborted: case SocketError.Shutdown: case SocketError.SystemNotReady: case SocketError.TooManyOpenSockets: this.Close(socketError.ToString()); return true; } return false; } /// <summary> /// 發送消息方法 /// </summary> internal int SendMsg(byte[] buffer) { int size = 0; try { if (!this.IsDispose) { size = this._Socket.Send(buffer, 0, buffer.Length, SocketFlags.None, out SenderError); CheckSocketError(SenderError); } } catch (System.ObjectDisposedException) { this.Close("鏈接已經被關閉"); } catch (System.Net.Sockets.SocketException) { this.Close("鏈接已經被關閉"); } buffer = null; return size; } }
上面我們事先了socket的異步接受消息,和同步發送消息已經關閉釋放資源代碼
接受消息net底層提供的接受消息的方法有很多,為什么我們要選擇上面所寫的呢?那是為了兼容U3D,silverlight, wpf, wp, wf,等程序可執行,不在重復做相同工作。
現在我們來創建一個實現類 TSocketClient
public class TSocketClient : TSocketBase { /// <summary> /// 是否是服務器端的資源 /// </summary> private bool isServer = false; /// <summary> /// 客戶端主動請求服務器 /// </summary> /// <param name="ip"></param> /// <param name="port"></param> public TSocketClient(string ip = "127.0.0.1", int port = 9527) { isServer = false; this._Socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this._Socket.Connect(ip, port); this.SetSocket(); this.ReceiveAsync(); } /// <summary> /// 這個是服務器收到有效鏈接初始化 /// </summary> /// <param name="socket"></param> public TSocketClient(Socket socket) { isServer = true; this._Socket = socket; this.SetSocket(); this.ReceiveAsync(); } /// <summary> /// 收到消息后 /// </summary> /// <param name="rbuff"></param> public override void Receive(byte[] rbuff) { Console.WriteLine("Receive Msg:" + System.Text.UTF8Encoding.Default.GetString(rbuff)); if (isServer) { this.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Client!")); } } }
因為是測試示例,所以我把服務器和客戶端實現類寫成了,只是用來不同的構造函數來區分,是客戶端還是服務器的標識
接下來我們測試一下代碼
class Program { static void Main(string[] args) { TCPListener tcp = new TCPListener(); TSocketClient client = new TSocketClient(); client.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Server!")); Console.ReadLine(); } }
運行結果看出,我們連接成功並且發送消息成功。