1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.Linq;
|
---|
4 | using System.Text;
|
---|
5 | using System.IO;
|
---|
6 | using System.Net;
|
---|
7 | using System.Net.Sockets;
|
---|
8 | using System.Threading;
|
---|
9 |
|
---|
10 | namespace UEUserGuide
|
---|
11 | {
|
---|
12 | /// <summary>
|
---|
13 | /// Implement a TCP client/listener.
|
---|
14 | /// </summary>
|
---|
15 | public class NetworkHelper
|
---|
16 | {
|
---|
17 | ///////////////////////////////////////////////////////////////////////
|
---|
18 | #region Internal fields
|
---|
19 |
|
---|
20 | /// <summary>
|
---|
21 | /// IP address.
|
---|
22 | /// </summary>
|
---|
23 | private IPAddress _address;
|
---|
24 |
|
---|
25 | /// <summary>
|
---|
26 | /// IP port.
|
---|
27 | /// </summary>
|
---|
28 | private int _port = -1;
|
---|
29 |
|
---|
30 | /// <summary>
|
---|
31 | /// Server instance.
|
---|
32 | /// </summary>
|
---|
33 | private TcpListener _server;
|
---|
34 |
|
---|
35 | /// <summary>
|
---|
36 | /// Client instance.
|
---|
37 | /// </summary>
|
---|
38 | private TcpClient _client;
|
---|
39 |
|
---|
40 | /// <summary>
|
---|
41 | /// End point reference.
|
---|
42 | /// </summary>
|
---|
43 | private NetworkStream _stream;
|
---|
44 |
|
---|
45 | #endregion Internal fields
|
---|
46 |
|
---|
47 | ///////////////////////////////////////////////////////////////////////
|
---|
48 | #region Static methods
|
---|
49 |
|
---|
50 | /// <summary>
|
---|
51 | /// Create a new instance of TcpClient from specified instance.
|
---|
52 | /// <remarks>This method acts like a copy ctor.</remarks>
|
---|
53 | /// </summary>
|
---|
54 | /// <param name="client">Client reference.</param>
|
---|
55 | /// <returns>The new instance on success, null otherwise.</returns>
|
---|
56 | private static NetworkHelper Create(TcpClient client)
|
---|
57 | {
|
---|
58 | // Sanity check.
|
---|
59 | if (client == null)
|
---|
60 | {
|
---|
61 | UEUserGuide.Logger.Instance.ErrorLogger("NetworkHelper: Client instance is null.");
|
---|
62 | return null;
|
---|
63 | }
|
---|
64 |
|
---|
65 | return new NetworkHelper(client);
|
---|
66 | }
|
---|
67 |
|
---|
68 | #endregion Static methods
|
---|
69 |
|
---|
70 | ///////////////////////////////////////////////////////////////////////
|
---|
71 | #region ctors
|
---|
72 |
|
---|
73 | /// <summary>
|
---|
74 | /// Default ctor.
|
---|
75 | /// </summary>
|
---|
76 | public NetworkHelper()
|
---|
77 | {
|
---|
78 | _address = null;
|
---|
79 | _port = -1;
|
---|
80 | _server = null;
|
---|
81 | _client = null;
|
---|
82 | }
|
---|
83 |
|
---|
84 | /// <summary>
|
---|
85 | /// Builder ctor used in server part.
|
---|
86 | /// </summary>
|
---|
87 | /// <param name="client"></param>
|
---|
88 | private NetworkHelper(TcpClient client)
|
---|
89 | {
|
---|
90 | _client = client;
|
---|
91 | _client.NoDelay = true;
|
---|
92 | _stream = _client.GetStream();
|
---|
93 | }
|
---|
94 |
|
---|
95 | #endregion ctors
|
---|
96 |
|
---|
97 | ///////////////////////////////////////////////////////////////////////
|
---|
98 | #region INetwork iface implementation
|
---|
99 |
|
---|
100 | ///////////////////////////////////////////////////////////////////////
|
---|
101 | #region Initialization part
|
---|
102 |
|
---|
103 | /// <summary>
|
---|
104 | /// Initialize the instance of TCP client or server.
|
---|
105 | /// </summary>
|
---|
106 | /// <param name="address">IP address to use for the communication.</param>
|
---|
107 | /// <param name="port">Port number</param>
|
---|
108 | /// <returns>true on success, false otherwise.</returns>
|
---|
109 | public bool Initialize(string address, int port)
|
---|
110 | {
|
---|
111 | try
|
---|
112 | {
|
---|
113 | _port = port;
|
---|
114 | _address = IPAddress.Parse(address);
|
---|
115 |
|
---|
116 | return true;
|
---|
117 | }
|
---|
118 | catch (Exception e)
|
---|
119 | {
|
---|
120 | Logger.Instance.ErrorLogger("NetworkTcp.Initialize: {0}", e);
|
---|
121 | }
|
---|
122 |
|
---|
123 | return false;
|
---|
124 | }
|
---|
125 |
|
---|
126 | /// <summary>
|
---|
127 | /// Uninitialize the current instance.
|
---|
128 | /// </summary>
|
---|
129 | /// <returns>true on success, false otherwise.</returns>
|
---|
130 | public bool Uninitialize()
|
---|
131 | {
|
---|
132 | Close();
|
---|
133 |
|
---|
134 | return true;
|
---|
135 | }
|
---|
136 |
|
---|
137 | #endregion Initialization part
|
---|
138 |
|
---|
139 | ///////////////////////////////////////////////////////////////////////
|
---|
140 | #region Server methods
|
---|
141 |
|
---|
142 | /// <summary>
|
---|
143 | /// Start the TCP server.
|
---|
144 | /// <seealso cref="Initialize"/> method must be called before.
|
---|
145 | /// </summary>
|
---|
146 | public void Start()
|
---|
147 | {
|
---|
148 | _server = new TcpListener(_address, _port);
|
---|
149 | _server.ExclusiveAddressUse = false;
|
---|
150 | _server.Server.NoDelay = true;
|
---|
151 | _server.Start();
|
---|
152 | // To prevent multiple listener instance.
|
---|
153 | Thread.Sleep(1000);
|
---|
154 | }
|
---|
155 |
|
---|
156 | /// <summary>
|
---|
157 | /// Stop the TCP server.
|
---|
158 | /// <seealso cref="Initialize"/> method must be called before.
|
---|
159 | /// </summary>
|
---|
160 | public void Stop()
|
---|
161 | {
|
---|
162 | if (_server != null)
|
---|
163 | {
|
---|
164 | _server.Stop();
|
---|
165 | _server = null;
|
---|
166 | }
|
---|
167 | }
|
---|
168 |
|
---|
169 | /// <summary>
|
---|
170 | /// Accept incoming connection.
|
---|
171 | /// </summary>
|
---|
172 | /// <returns>New client instance.</returns>
|
---|
173 | public NetworkHelper AcceptClient()
|
---|
174 | {
|
---|
175 | TcpClient client = _server.AcceptTcpClient();
|
---|
176 | return NetworkHelper.Create(client);
|
---|
177 | }
|
---|
178 |
|
---|
179 | #endregion Server methods
|
---|
180 |
|
---|
181 | ///////////////////////////////////////////////////////////////////////
|
---|
182 | #region Client methods
|
---|
183 |
|
---|
184 | /// <summary>
|
---|
185 | /// Initiate a connection.
|
---|
186 | /// </summary>
|
---|
187 | public void Connect()
|
---|
188 | {
|
---|
189 | if (_client != null)
|
---|
190 | {
|
---|
191 | return;
|
---|
192 | }
|
---|
193 |
|
---|
194 | _client = new TcpClient();
|
---|
195 | _client.NoDelay = true;
|
---|
196 | _client.Connect(_address, _port);
|
---|
197 | // Get a stream object for reading and writing
|
---|
198 | _stream = _client.GetStream();
|
---|
199 | }
|
---|
200 |
|
---|
201 | /// <summary>
|
---|
202 | /// Initiate a connection with login/password..
|
---|
203 | /// </summary>
|
---|
204 | /// <param name="login">Login to pass.</param>
|
---|
205 | /// <param name="password">Password to pass.</param>
|
---|
206 | public void Connect(string login, string password)
|
---|
207 | {
|
---|
208 | throw new NotImplementedException();
|
---|
209 | }
|
---|
210 |
|
---|
211 | /// <summary>
|
---|
212 | /// Terminate the connection.
|
---|
213 | /// </summary>
|
---|
214 | public void Close()
|
---|
215 | {
|
---|
216 | if (_client != null)
|
---|
217 | {
|
---|
218 | try
|
---|
219 | {
|
---|
220 | if (_stream != null)
|
---|
221 | {
|
---|
222 | _stream.Close();
|
---|
223 | }
|
---|
224 | _client.Close();
|
---|
225 | }
|
---|
226 | catch
|
---|
227 | {
|
---|
228 | }
|
---|
229 | finally
|
---|
230 | {
|
---|
231 | _client = null;
|
---|
232 | _stream = null;
|
---|
233 | }
|
---|
234 | }
|
---|
235 | }
|
---|
236 |
|
---|
237 | #endregion Client methods
|
---|
238 |
|
---|
239 | ///////////////////////////////////////////////////////////////////////
|
---|
240 | #region Data access methods
|
---|
241 |
|
---|
242 | /// <summary>
|
---|
243 | /// Received datas from remote.
|
---|
244 | /// </summary>
|
---|
245 | /// <param name="buffer">The buffer to store the datas. Set to null on error.</param>
|
---|
246 | /// <returns>The number of bytes received on success, -1 otherwise.</returns>
|
---|
247 | public int Receive(out byte[] buffer)
|
---|
248 | {
|
---|
249 | if (_stream != null)
|
---|
250 | {
|
---|
251 | // read size of the packet first.
|
---|
252 | byte[] length = new byte[sizeof(int)];
|
---|
253 | _stream.Read(length, 0, length.Length);
|
---|
254 | int totalBytes = BitConverter.ToInt32(length, 0);
|
---|
255 | buffer = new byte[totalBytes];
|
---|
256 | int readBytes = _stream.Read(buffer, 0, buffer.Length);
|
---|
257 | while (readBytes < totalBytes)
|
---|
258 | {
|
---|
259 | byte[] next = new byte[totalBytes - readBytes];
|
---|
260 | readBytes += _stream.Read(next, 0, next.Length);
|
---|
261 | buffer.Concat<byte>(next);
|
---|
262 | }
|
---|
263 |
|
---|
264 | return buffer.Length;
|
---|
265 | }
|
---|
266 |
|
---|
267 | buffer = null;
|
---|
268 | return -1;
|
---|
269 | }
|
---|
270 |
|
---|
271 | /// <summary>
|
---|
272 | /// Received strings from remote.
|
---|
273 | /// </summary>
|
---|
274 | /// <param name="buffer">The buffer to store the strings. Set to null on error.</param>
|
---|
275 | /// <returns>The number of bytes received on success, -1 otherwise.</returns>
|
---|
276 | public int Receive(out string buffer)
|
---|
277 | {
|
---|
278 | if (_stream != null)
|
---|
279 | {
|
---|
280 | if (_stream.DataAvailable)
|
---|
281 | {
|
---|
282 | byte[] inbuf = new byte[512];
|
---|
283 |
|
---|
284 | IAsyncResult ar = _stream.BeginRead(inbuf, 0, 512, null, null);
|
---|
285 | int bytesRead = _stream.EndRead(ar);
|
---|
286 | if (ar.IsCompleted)
|
---|
287 | {
|
---|
288 | buffer = System.Text.Encoding.ASCII.GetString(inbuf, 0, bytesRead);
|
---|
289 | return buffer.Length;
|
---|
290 | }
|
---|
291 | }
|
---|
292 | else
|
---|
293 | {
|
---|
294 | buffer = "";
|
---|
295 | return 0;
|
---|
296 | }
|
---|
297 | }
|
---|
298 |
|
---|
299 | buffer = null;
|
---|
300 | return -1;
|
---|
301 | }
|
---|
302 |
|
---|
303 | /// <summary>
|
---|
304 | /// Send data to remote.
|
---|
305 | /// </summary>
|
---|
306 | /// <param name="buffer">Data to send.</param>
|
---|
307 | /// <param name="size">The number of byte to send.</param>
|
---|
308 | /// <returns>The number of bytes sent on success, -1 otherwise.</returns>
|
---|
309 | public int Send(byte[] buffer, int size)
|
---|
310 | {
|
---|
311 | if (_stream != null)
|
---|
312 | {
|
---|
313 | // Sanity checks.
|
---|
314 | if ((buffer == null) || (size == 0))
|
---|
315 | {
|
---|
316 | return 0;
|
---|
317 | }
|
---|
318 |
|
---|
319 | // Send size of packet first.
|
---|
320 | byte[] length = BitConverter.GetBytes(size);
|
---|
321 | _stream.Write(length , 0, length.Length);
|
---|
322 | // Send the packet after.
|
---|
323 | _stream.Write(buffer, 0, size);
|
---|
324 | _stream.Flush();
|
---|
325 | return size;
|
---|
326 | }
|
---|
327 |
|
---|
328 | return -1;
|
---|
329 | }
|
---|
330 |
|
---|
331 | /// <summary>
|
---|
332 | /// Send string to remote.
|
---|
333 | /// </summary>
|
---|
334 | /// <param name="buffer">String to send.</param>
|
---|
335 | /// <returns>The received string length on success, -1 otherwise.</returns>
|
---|
336 | public int Send(string buffer)
|
---|
337 | {
|
---|
338 | if (_stream != null)
|
---|
339 | {
|
---|
340 | // Sanity checks.
|
---|
341 | if (string.IsNullOrEmpty(buffer))
|
---|
342 | {
|
---|
343 | return 0;
|
---|
344 | }
|
---|
345 | byte[] output = System.Text.Encoding.ASCII.GetBytes(buffer);
|
---|
346 | _stream.Write(output, 0, output.Length);
|
---|
347 | _stream.Flush();
|
---|
348 | return output.Length;
|
---|
349 | }
|
---|
350 |
|
---|
351 | return -1;
|
---|
352 | }
|
---|
353 |
|
---|
354 | #endregion Data access methods
|
---|
355 |
|
---|
356 | #endregion INetwork iface implementation
|
---|
357 | }
|
---|
358 | }
|
---|