SHOW:
|
|
- or go back to the newest paste.
1 | using System; | |
2 | using System.Collections.Generic; | |
3 | using System.Net; | |
4 | using System.Net.Sockets; | |
5 | using System.Linq; | |
6 | using System.Text; | |
7 | using System.Threading; | |
8 | ||
9 | namespace Phurious.Android.Blazr | |
10 | { | |
11 | /// <summary> | |
12 | /// An Asynchronous TCP Server that makes use of system managed threads | |
13 | /// and callbacks to stop the server ever locking up. | |
14 | /// </summary> | |
15 | public class AsyncTcpServer | |
16 | { | |
17 | /// <summary> | |
18 | /// The encoding to use when sending / receiving strings. | |
19 | /// </summary> | |
20 | public Encoding Encoding { get; set; } | |
21 | ||
22 | private TcpListener _tcpListener; | |
23 | private List<AsyncTcpClient> _clients; | |
24 | ||
25 | /// <summary> | |
26 | /// Constructor for a new server using an IPAddress and Port | |
27 | /// </summary> | |
28 | /// <param name="localaddr">The Local IP Address for the server.</param> | |
29 | /// <param name="port">The port for the server.</param> | |
30 | public AsyncTcpServer(IPAddress localaddr, int port) | |
31 | : this() | |
32 | { | |
33 | _tcpListener = new TcpListener(localaddr, port); | |
34 | } | |
35 | ||
36 | /// <summary> | |
37 | /// Constructor for a new server using an end point | |
38 | /// </summary> | |
39 | /// <param name="localEP">The local end point for the server.</param> | |
40 | public AsyncTcpServer(IPEndPoint localEP) | |
41 | : this() | |
42 | { | |
43 | _tcpListener = new TcpListener(localEP); | |
44 | } | |
45 | ||
46 | /// <summary> | |
47 | /// Private constructor for the common constructor operations. | |
48 | /// </summary> | |
49 | private AsyncTcpServer() | |
50 | { | |
51 | this.Encoding = Encoding.ASCII; | |
52 | this._clients = new List<AsyncTcpClient>(); | |
53 | } | |
54 | ||
55 | /// <summary> | |
56 | /// An enumerable collection of all the currently connected tcp clients | |
57 | /// </summary> | |
58 | public IEnumerable<TcpClient> TcpClients | |
59 | { | |
60 | get | |
61 | { | |
62 | foreach (AsyncTcpClient client in this._clients) | |
63 | { | |
64 | yield return client.TcpClient; | |
65 | } | |
66 | } | |
67 | } | |
68 | ||
69 | /// <summary> | |
70 | /// Starts the TCP Server listening for new clients. | |
71 | /// </summary> | |
72 | public void Listen() | |
73 | { | |
74 | this._tcpListener.Start(); | |
75 | this._tcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, null); | |
76 | } | |
77 | ||
78 | ||
79 | ||
80 | /// <summary> | |
81 | /// Stops the TCP Server listening for new clients and disconnects | |
82 | /// any currently connected clients. | |
83 | /// </summary> | |
84 | public void StopListening() | |
85 | { | |
86 | this._tcpListener.Stop(); | |
87 | lock (this._clients) | |
88 | { | |
89 | foreach (AsyncTcpClient client in this._clients) | |
90 | { | |
91 | client.TcpClient.Client.Disconnect(false); | |
92 | } | |
93 | ||
94 | this._clients.Clear(); | |
95 | } | |
96 | } | |
97 | ||
98 | /// <summary> | |
99 | /// Writes a string to a given TCP Client | |
100 | /// </summary> | |
101 | /// <param name="tcpClient">The client to write to</param> | |
102 | /// <param name="data">The string to send.</param> | |
103 | public void Write(TcpClient tcpClient, String data) | |
104 | { | |
105 | byte[] bytes = this.Encoding.GetBytes(data); | |
106 | ||
107 | Write(tcpClient, bytes); | |
108 | } | |
109 | ||
110 | ||
111 | ||
112 | /// <summary> | |
113 | /// Writes a string to all clients connected. | |
114 | /// </summary> | |
115 | /// <param name="data">The string to send.</param> | |
116 | public void Write(String data) | |
117 | { | |
118 | foreach (AsyncTcpClient client in this._clients) | |
119 | { | |
120 | Write(client.TcpClient, data); | |
121 | } | |
122 | } | |
123 | ||
124 | /// <summary> | |
125 | /// Writes a byte array to all clients connected. | |
126 | /// </summary> | |
127 | /// <param name="bytes">The bytes to send.</param> | |
128 | public void Write(Byte[] bytes) | |
129 | { | |
130 | foreach (AsyncTcpClient client in this._clients) | |
131 | { | |
132 | Write(client.TcpClient, bytes); | |
133 | } | |
134 | } | |
135 | ||
136 | /// <summary> | |
137 | /// Writes a byte array to a given TCP Client | |
138 | /// </summary> | |
139 | /// <param name="tcpClient">The client to write to</param> | |
140 | /// <param name="bytes">The bytes to send</param> | |
141 | public void Write(TcpClient tcpClient, Byte[] bytes) | |
142 | { | |
143 | NetworkStream networkStream = tcpClient.GetStream(); | |
144 | ||
145 | networkStream.BeginWrite(bytes, 0, bytes.Length, WriteCallback, tcpClient); | |
146 | } | |
147 | ||
148 | public void Write(AsyncTcpClient client, Byte[] bytes) | |
149 | { | |
150 | NetworkStream networkStream = client.NetworkStream; | |
151 | ||
152 | networkStream.BeginWrite(bytes, 0, bytes.Length, WriteCallback, client.TcpClient); | |
153 | } | |
154 | ||
155 | /// <summary> | |
156 | /// Callback for the write opertaion. | |
157 | /// </summary> | |
158 | /// <param name="result">The async result object</param> | |
159 | private void WriteCallback(IAsyncResult result) | |
160 | { | |
161 | TcpClient tcpClient = result.AsyncState as TcpClient; | |
162 | NetworkStream networkStream = tcpClient.GetStream(); | |
163 | ||
164 | networkStream.EndWrite(result); | |
165 | } | |
166 | ||
167 | /// <summary> | |
168 | /// Callback for the accept tcp client opertaion. | |
169 | /// </summary> | |
170 | /// <param name="result">The async result object</param> | |
171 | private void AcceptTcpClientCallback(IAsyncResult result) | |
172 | { | |
173 | TcpClient tcpClient = _tcpListener.EndAcceptTcpClient(result); | |
174 | byte[] buffer = new byte[tcpClient.ReceiveBufferSize]; | |
175 | AsyncTcpClient client = new AsyncTcpClient(tcpClient, buffer); | |
176 | client.DataReceived += new AsyncTcpClient.DataReceivedHandler(Program.ProcessCommand); | |
177 | ||
178 | lock (this._clients) | |
179 | { | |
180 | this._clients.Add(client); | |
181 | } | |
182 | ||
183 | NetworkStream networkStream = client.NetworkStream; | |
184 | ||
185 | networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, ReadCallback, client); | |
186 | ||
187 | _tcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, null); | |
188 | } | |
189 | ||
190 | /// <summary> | |
191 | /// Callback for the read opertaion. | |
192 | /// </summary> | |
193 | /// <param name="result">The async result object</param> | |
194 | private void ReadCallback(IAsyncResult result) | |
195 | { | |
196 | AsyncTcpClient client = result.AsyncState as AsyncTcpClient; | |
197 | ||
198 | if (client == null) return; | |
199 | ||
200 | NetworkStream networkStream = client.NetworkStream; | |
201 | ||
202 | int read = networkStream.EndRead(result); | |
203 | ||
204 | if (read == 0) | |
205 | { | |
206 | lock (this._clients) | |
207 | { | |
208 | this._clients.Remove(client); | |
209 | return; | |
210 | } | |
211 | } | |
212 | ||
213 | string data = this.Encoding.GetString(client.Buffer, 0, read); | |
214 | ||
215 | networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, ReadCallback, client); | |
216 | } | |
217 | } | |
218 | ||
219 | /// <summary> | |
220 | /// Internal class to join the TCP client and buffer together | |
221 | /// for easy management in the server | |
222 | /// </summary> | |
223 | public class AsyncTcpClient | |
224 | { | |
225 | public delegate void DataReceivedHandler(AsyncTcpClient client); | |
226 | public event DataReceivedHandler DataReceived; | |
227 | ||
228 | /// <summary> | |
229 | /// The encoding to use when sending / receiving strings. | |
230 | /// </summary> | |
231 | public Encoding Encoding { get; set; } | |
232 | ||
233 | private TcpClient _tcpClient = null; | |
234 | private Byte[] _buffer = null; | |
235 | ||
236 | /// <summary> | |
237 | /// Constructor for a new Client | |
238 | /// </summary> | |
239 | /// <param name="tcpClient">The TCP client</param> | |
240 | /// <param name="buffer">The byte array buffer</param> | |
241 | public AsyncTcpClient(TcpClient tcpClient, Byte[] buffer) | |
242 | : this() | |
243 | { | |
244 | if (tcpClient == null) throw new ArgumentNullException("tcpClient is null"); | |
245 | ||
246 | if (buffer == null) throw new ArgumentNullException("Buffer is null"); | |
247 | ||
248 | this.TcpClient = tcpClient; | |
249 | ||
250 | this.Buffer = buffer; | |
251 | } | |
252 | ||
253 | private AsyncTcpClient() | |
254 | { | |
255 | this.Encoding = Encoding.ASCII; | |
256 | } | |
257 | ||
258 | /// <summary> | |
259 | /// Gets the TCP Client | |
260 | /// </summary> | |
261 | public TcpClient TcpClient | |
262 | { | |
263 | get | |
264 | { | |
265 | return _tcpClient; | |
266 | } | |
267 | set | |
268 | { | |
269 | _tcpClient = value; | |
270 | } | |
271 | } | |
272 | ||
273 | /// <summary> | |
274 | /// Gets the Buffer. | |
275 | /// </summary> | |
276 | public Byte[] Buffer | |
277 | { | |
278 | get | |
279 | { | |
280 | return _buffer; | |
281 | } | |
282 | set | |
283 | { | |
284 | _buffer = value; | |
285 | if (this.DataReceived != null) this.DataReceived(this); | |
286 | } | |
287 | } | |
288 | ||
289 | ||
290 | /// <summary> | |
291 | /// Gets the network stream | |
292 | /// </summary> | |
293 | public NetworkStream NetworkStream | |
294 | { | |
295 | get | |
296 | { | |
297 | return TcpClient.GetStream(); | |
298 | } | |
299 | } | |
300 | } | |
301 | } |