看了系列一 我們開啟了對socket tcp的監聽狀態,那麼這一章我們來講解怎麼創建socket的通信代碼
我新建一個類 TSocketBase
1 public abstract class TSocketBase
2 {
3 //封裝socket
4 internal Socket _Socket;
5 //回調
6 private AsyncCallback aCallback;
7 //接受數據的緩沖區
8 private byte[] Buffers;
9 //標識是否已經釋放
10 private volatile bool IsDispose;
11 //10K的緩沖區空間
12 private int BufferSize = 10 * 1024;
13 //收取消息狀態碼
14 private SocketError ReceiveError;
15 //發送消息的狀態碼
16 private SocketError SenderError;
17 //每一次接受到的字節數
18 private int ReceiveSize = 0;
19 //接受空消息次數
20 byte ZeroCount = 0;
21
22 public abstract void Receive(byte[] rbuff);
23
24 public void SetSocket()
25 {
26 this.aCallback = new AsyncCallback(this.ReceiveCallback);
27 this.IsDispose = false;
28 this._Socket.ReceiveBufferSize = this.BufferSize;
29 this._Socket.SendBufferSize = this.BufferSize;
30 this.Buffers = new byte[this.BufferSize];
31 }
32
33
34 /// <summary>
35 /// 關閉並釋放資源
36 /// </summary>
37 /// <param name="msg"></param>
38 public void Close(string msg)
39 {
40 if (!this.IsDispose)
41 {
42 this.IsDispose = true;
43 try
44 {
45 try { this._Socket.Close(); }
46 catch { }
47 IDisposable disposable = this._Socket;
48 if (disposable != null) { disposable.Dispose(); }
49 this.Buffers = null;
50 GC.SuppressFinalize(this);
51 }
52 catch (Exception) { }
53 }
54 }
55
56
57 /// <summary>
58 /// 遞歸接收消息方法
59 /// </summary>
60 internal void ReceiveAsync()
61 {
62 try
63 {
64 if (!this.IsDispose && this._Socket.Connected)
65 {
66 this._Socket.BeginReceive(this.Buffers, 0, this.BufferSize, SocketFlags.None, out SenderError, this.aCallback, this);
67 CheckSocketError(ReceiveError);
68 }
69 }
70 catch (System.Net.Sockets.SocketException) { this.Close("鏈接已經被關閉"); }
71 catch (System.ObjectDisposedException) { this.Close("鏈接已經被關閉"); }
72 }
73
74
75
76 /// <summary>
77 /// 接收消息回調函數
78 /// </summary>
79 /// <param name="iar"></param>
80 private void ReceiveCallback(IAsyncResult iar)
81 {
82 if (!this.IsDispose)
83 {
84 try
85 {
86 //接受消息
87 ReceiveSize = _Socket.EndReceive(iar, out ReceiveError);
88 //檢查狀態碼
89 if (!CheckSocketError(ReceiveError) && SocketError.Success == ReceiveError)
90 {
91 //判斷接受的字節數
92 if (ReceiveSize > 0)
93 {
94 byte[] rbuff = new byte[ReceiveSize];
95 Array.Copy(this.Buffers, rbuff, ReceiveSize);
96 this.Receive(rbuff);
97 //重置連續收到空字節數
98 ZeroCount = 0;
99 //繼續開始異步接受消息
100 ReceiveAsync();
101 }
102 else
103 {
104 ZeroCount++;
105 if (ZeroCount == 5) { this.Close("錯誤鏈接"); }
106 }
107 }
108 }
109 catch (System.Net.Sockets.SocketException) { this.Close("鏈接已經被關閉"); }
110 catch (System.ObjectDisposedException) { this.Close("鏈接已經被關閉"); }
111 }
112 }
113
114 /// <summary>
115 /// 錯誤判斷
116 /// </summary>
117 /// <param name="socketError"></param>
118 /// <returns></returns>
119 bool CheckSocketError(SocketError socketError)
120 {
121 switch ((socketError))
122 {
123 case SocketError.SocketError:
124 case SocketError.VersionNotSupported:
125 case SocketError.TryAgain:
126 case SocketError.ProtocolFamilyNotSupported:
127 case SocketError.ConnectionAborted:
128 case SocketError.ConnectionRefused:
129 case SocketError.ConnectionReset:
130 case SocketError.Disconnecting:
131 case SocketError.HostDown:
132 case SocketError.HostNotFound:
133 case SocketError.HostUnreachable:
134 case SocketError.NetworkDown:
135 case SocketError.NetworkReset:
136 case SocketError.NetworkUnreachable:
137 case SocketError.NoData:
138 case SocketError.OperationAborted:
139 case SocketError.Shutdown:
140 case SocketError.SystemNotReady:
141 case SocketError.TooManyOpenSockets:
142 this.Close(socketError.ToString());
143 return true;
144 }
145 return false;
146 }
147
148 /// <summary>
149 /// 發送消息方法
150 /// </summary>
151 internal int SendMsg(byte[] buffer)
152 {
153 int size = 0;
154 try
155 {
156 if (!this.IsDispose)
157 {
158 size = this._Socket.Send(buffer, 0, buffer.Length, SocketFlags.None, out SenderError);
159 CheckSocketError(SenderError);
160 }
161 }
162 catch (System.ObjectDisposedException) { this.Close("鏈接已經被關閉"); }
163 catch (System.Net.Sockets.SocketException) { this.Close("鏈接已經被關閉"); }
164 buffer = null;
165 return size;
166 }
167 }
上面我們事先了socket的異步接受消息,和同步發送消息已經關閉釋放資源代碼
接受消息net底層提供的接受消息的方法有很多,為什麼我們要選擇上面所寫的呢?那是為了兼容U3D,silverlight, wpf, wp, wf,等程序可執行,不在重復做相同工作。
現在我們來創建一個實現類 TSocketClient
1 public class TSocketClient : TSocketBase
2 {
3 /// <summary>
4 /// 是否是服務器端的資源
5 /// </summary>
6 bool isServer = false;
7
8 /// <summary>
9 /// 客戶端主動請求服務器
10 /// </summary>
11 /// <param name="ip"></param>
12 /// <param name="port"></param>
13 public TSocketClient(string ip = "127.0.0.1", int port = 9527)
14 {
15 isServer = false;
16 this._Socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
17 this._Socket.Connect(ip, port);
18 this.SetSocket();
19 this.ReceiveAsync();
20 }
21 /// <summary>
22 /// 這個是服務器收到有效鏈接初始化
23 /// </summary>
24 /// <param name="socket"></param>
25 public TSocketClient(Socket socket)
26 {
27 isServer = true;
28 this._Socket = socket;
29 this.SetSocket();
30 this.ReceiveAsync();
31 }
32
33 /// <summary>
34 /// 收到消息後
35 /// </summary>
36 /// <param name="rbuff"></param>
37 public override void Receive(byte[] rbuff)
38 {
39 Console.WriteLine("Receive Msg:" + System.Text.UTF8Encoding.Default.GetString(rbuff));
40 if (isServer)
41 {
42 this.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Client!"));
43 }
44 }
45 }
因為是測試示例,所以我把服務器和客戶端實現類寫成了,只是用來不同的構造函數來區分,是客戶端還是服務器的標識
接下來我們測試一下代碼
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 TCPListener tcp = new TCPListener();
6 TSocketClient client = new TSocketClient();
7 client.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Server!"));
8 Console.ReadLine();
9 }
10 }

運行結果看出,我們連接成功並且發送消息成功。