C#非同步TCP伺服器完整實現
阿新 • • 發佈:2019-02-10
1 ///<summary>
2 /// 非同步TCP伺服器
3 ///</summary>
4 public class AsyncTcpServer : IDisposable
5 {
6 #region Fields
7
8 private TcpListener listener;
9 private List<TcpClientState> clients;
10 private bool disposed = false;
11
12 #endregion
13
14 #region Ctors
15
16 ///<summary>
17 /// 非同步TCP伺服器
18 ///</summary>
19 ///<param name="listenPort">監聽的埠</param>
20 public AsyncTcpServer(int listenPort)
21 : this(IPAddress.Any, listenPort)
22 {
23 }
24
25 ///<summary>
26 /// 非同步TCP伺服器
27 ///</summary>
28 ///<param name="localEP">監聽的終結點</param>
29 public AsyncTcpServer(IPEndPoint localEP)
30 : this(localEP.Address, localEP.Port)
31 {
32 }
33
34 ///<summary>
35 /// 非同步TCP伺服器
36 ///</summary>
37 ///<param name="localIPAddress"> 監聽的IP地址</param>
38 ///<param name="listenPort">監聽的埠</param>
39 public AsyncTcpServer(IPAddress localIPAddress, int listenPort)
40 {
41 Address = localIPAddress;
42 Port = listenPort;
43 this.Encoding = Encoding.Default;
44
45 clients = new List<TcpClientState>();
46
47 listener = new TcpListener(Address, Port);
48 listener.AllowNatTraversal(true);
49 }
50
51 #endregion
52
53 #region Properties
54
55 ///<summary>
56 /// 伺服器是否正在執行
57 ///</summary>
58 public bool IsRunning { get; private set; }
59 ///<summary>
60 /// 監聽的IP地址
61 ///</summary>
62 public IPAddress Address { get; private set; }
63 ///<summary>
64 /// 監聽的埠
65 ///</summary>
66 public int Port { get; private set; }
67 ///<summary>
68 /// 通訊使用的編碼
69 ///</summary>
70 public Encoding Encoding { get; set; }
71
72 #endregion
73
74 #region Server
75
76 ///<summary>
77 /// 啟動伺服器
78 ///</summary>
79 ///<returns>非同步TCP伺服器</returns>
80 public AsyncTcpServer Start()
81 {
82 if (!IsRunning)
83 {
84 IsRunning = true;
85 listener.Start();
86 listener.BeginAcceptTcpClient(
87 new AsyncCallback(HandleTcpClientAccepted), listener);
88 }
89 return this;
90 }
91
92 ///<summary>
93 /// 啟動伺服器
94 ///</summary>
95 ///<param name="backlog">
96 /// 伺服器所允許的掛起連線序列的最大長度
97 ///</param>
98 ///<returns>非同步TCP伺服器</returns>
99 public AsyncTcpServer Start(int backlog)
100 {
101 if (!IsRunning)
102 {
103 IsRunning = true;
104 listener.Start(backlog);
105 listener.BeginAcceptTcpClient(
106 new AsyncCallback(HandleTcpClientAccepted), listener);
107 }
108 return this;
109 }
110
111 ///<summary>
112 /// 停止伺服器
113 ///</summary>
114 ///<returns>非同步TCP伺服器</returns>
115 public AsyncTcpServer Stop()
116 {
117 if (IsRunning)
118 {
119 IsRunning = false;
120 listener.Stop();
121
122 lock (this.clients)
123 {
124 for (int i = 0; i < this.clients.Count; i++)
125 {
126 this.clients[i].TcpClient.Client.Disconnect(false);
127 }
128 this.clients.Clear();
129 }
130
131 }
132 return this;
133 }
134
135 #endregion
136
137 #region Receive
138
139 private void HandleTcpClientAccepted(IAsyncResult ar)
140 {
141 if (IsRunning)
142 {
143 TcpListener tcpListener = (TcpListener)ar.AsyncState;
144
145 TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar);
146 byte[] buffer = new byte[tcpClient.ReceiveBufferSize];
147
148 TcpClientState internalClient
149 = new TcpClientState(tcpClient, buffer);
150 lock (this.clients)
151 {
152 this.clients.Add(internalClient);
153 RaiseClientConnected(tcpClient);
154 }
155
156 NetworkStream networkStream = internalClient.NetworkStream;
157 networkStream.BeginRead(
158 internalClient.Buffer,
159 0,
160 internalClient.Buffer.Length,
161 HandleDatagramReceived,
162 internalClient);
163
164 tcpListener.BeginAcceptTcpClient(
165 new AsyncCallback(HandleTcpClientAccepted), ar.AsyncState);
166 }
167 }
168
169 private void HandleDatagramReceived(IAsyncResult ar)
170 {
171 if (IsRunning)
172 {
173 TcpClientState internalClient = (TcpClientState)ar.AsyncState;
174 NetworkStream networkStream = internalClient.NetworkStream;
175
176 int numberOfReadBytes = 0;
177 try
178 {
179 numberOfReadBytes = networkStream.EndRead(ar);
180 }
181 catch
182 {
183 numberOfReadBytes = 0;
184 }
185
186 if (numberOfReadBytes == 0)
187 {
188 // connection has been closed
189 lock (this.clients)
190 {
191 this.clients.Remove(internalClient);
192 RaiseClientDisconnected(internalClient.TcpClient);
193 return;
194 }
195 }
196
197 // received byte and trigger event notification
198 byte[] receivedBytes = new byte[numberOfReadBytes];
199 Buffer.BlockCopy(
200 internalClient.Buffer, 0,
201 receivedBytes, 0, numberOfReadBytes);
202 RaiseDatagramReceived(internalClient.TcpClient, receivedBytes);
203 RaisePlaintextReceived(internalClient.TcpClient, receivedBytes);
204
205 // continue listening for tcp datagram packets
206 networkStream.BeginRead(
207 internalClient.Buffer,
208 0,
209 internalClient.Buffer.Length,
210 HandleDatagramReceived,
211 internalClient);
212 }
213 }
214
215 #endregion
216
217 #region Events
218
219 ///<summary>
220 /// 接收到資料報文事件
221 ///</summary>
222 public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived;
223 ///<summary>
224 /// 接收到資料報文明文事件
225 ///</summary>
226 public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived;
227
228 private void RaiseDatagramReceived(TcpClient sender, byte[] datagram)
229 {
230 if (DatagramReceived != null)
231 {
232 DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram));
233 }
234 }
235
236 private void RaisePlaintextReceived(TcpClient sender, byte[] datagram)
237 {
238 if (PlaintextReceived != null)
239 {
240 PlaintextReceived(this, new TcpDatagramReceivedEventArgs<string>(
241 sender, this.Encoding.GetString(datagram, 0, datagram.Length)));
242 }
243 }
244
245 ///<summary>
246