PageRenderTime 1408ms CodeModel.GetById 15ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/Utilities/Tests/NetworkingTests.cs

#
C# | 808 lines | 485 code | 99 blank | 224 comment | 23 complexity | 74c1cf987ad63f4957e4c0b3668240cc MD5 | raw file
  1using System;
  2using System.Diagnostics;
  3using System.IO;
  4using System.Net;
  5using System.Net.Sockets;
  6using System.Threading;
  7using Delta.Utilities.Cryptography;
  8using Delta.Utilities.Helpers;
  9using Delta.Utilities.Networking;
 10using Delta.Utilities.Xml;
 11using NUnit.Framework;
 12
 13namespace Delta.Utilities.Tests
 14{
 15	/// <summary>
 16	/// Tests for Delta.Utilities.Networking (mostly BaseClient and BaseServer)
 17	/// </summary>
 18	internal class NetworkingTests
 19	{
 20		#region Helpers
 21
 22		#region TextClient
 23		/// <summary>
 24		/// Helper class for receiving client data and outputting it to the console
 25		/// </summary>
 26		public class TextClient : BaseClient
 27		{
 28			#region Constants
 29			public const string TestServer = "localhost";
 30
 31			public const string TestUsername = "TestUser";
 32			#endregion
 33
 34			#region Constructors
 35			/// <summary>
 36			/// Constructor to create TextClient for the server side.
 37			/// </summary>
 38			public TextClient(Socket setSocket, BaseServer setLinkToServer)
 39				: base(setSocket, TextServer.NumOfMessageTypes, setLinkToServer)
 40			{
 41			}
 42
 43			/// <summary>
 44			/// Constructor to create TextClient for the client side.
 45			/// </summary>
 46			public TextClient()
 47				: base(TestServer, TextServer.ServerPort, TextServer.NumOfMessageTypes,
 48					true, TestUsername)
 49			{
 50			}
 51			#endregion
 52
 53			#region Methods (Private)
 54
 55			#region OnMessageReceived
 56			/// <summary>
 57			/// Every time we receive a message, we show it in the console and log
 58			/// </summary>
 59			protected override void OnMessageReceived(byte messageType,
 60				BinaryReader data)
 61			{
 62				if (messageType == TextServer.TextMessageType)
 63				{
 64					Log.Info("TextMessage received: " +
 65					         data.ReadString());
 66				}
 67				else if (messageType == TextServer.EmptyMessageType)
 68				{
 69					Log.Info("EmptyMessage received");
 70				}
 71				else
 72				{
 73					Log.Info("Received unknown message type=" + messageType +
 74					         " from server");
 75				}
 76			}
 77			#endregion
 78
 79			#endregion
 80		}
 81		#endregion
 82
 83		#region TestTcpServer
 84		/// <summary>
 85		/// Test tcp server
 86		/// </summary>
 87		public class TestTcpServer : BaseServer
 88		{
 89			#region Constants
 90			public const int ServerPort = 12345;
 91			#endregion
 92
 93			#region Constructors
 94			/// <summary>
 95			/// Create test tcp server
 96			/// </summary>
 97			public TestTcpServer()
 98				: base(ServerPort, BaseClient.NumberOfBasicMessageTypes)
 99			{
100			}
101			#endregion
102
103			#region Methods (Private)
104
105			#region CreateClient
106			/// <summary>
107			/// Create TextClient
108			/// </summary>
109			protected override BaseClient CreateClient(Socket clientSocket)
110			{
111				return new TextClient(clientSocket, this);
112			}
113			#endregion
114
115			#region OnMessageReceived
116			/// <summary>
117			/// On message received
118			/// </summary>
119			protected internal override void OnMessageReceived(BaseClient client,
120				byte messageType, BinaryReader data)
121			{
122				if (messageType == (byte)BasicMessageTypes.TextMessage)
123				{
124					Console.WriteLine("Received TextMessage on server from client=" +
125					                  client + ": " + data.ReadString());
126				}
127				else
128				{
129					Console.WriteLine("Received unknown message type=" + messageType +
130					                  " on server from client=" + client);
131				}
132			}
133			#endregion
134
135			#region OnClientLogin
136			/// <summary>
137			/// This method is called for every client that successfully connects.
138			/// </summary>
139			protected override bool OnClientLogin(BaseClient client,
140				BinaryReader data)
141			{
142				base.OnClientLogin(client, data);
143				Console.WriteLine("TestTcpServer.OnClientLogin " + client);
144				return true;
145			}
146			#endregion
147
148			#region OnClientDisconnected
149			/// <summary>
150			/// This method is called for every client disconnect.
151			/// </summary>
152			protected override void OnClientDisconnected(BaseClient client)
153			{
154				Console.WriteLine("TestTcpServer.OnClientDisconnected " + client);
155				base.OnClientDisconnected(client);
156			}
157			#endregion
158
159			#endregion
160		}
161		#endregion
162
163		#region TestEncryptedServer
164		/// <summary>
165		/// Test encrypted server that uses AES cryptography for network
166		/// transmission and even protects the AES seed value with RSA encryption.
167		/// </summary>
168		public class TestEncryptedServer : BaseServer
169		{
170			#region Constants
171			/// <summary>
172			/// Server port used for this test server
173			/// </summary>
174			public const int ServerPort = 12345;
175			#endregion
176
177			#region aesPrivateKey (Static)
178			/// <summary>
179			/// AES private key that must be known both to the client and the server.
180			/// </summary>
181			public static byte[] aesPrivateKey = AES.CreatePrivateKey();
182			#endregion
183
184			#region secretRsaKey (Static)
185			/// <summary>
186			/// Note: In order for this to work a Private.RSA.key file must exist,
187			/// start the CryptographyTests.TestRsaCrypto unit test to generate.
188			/// </summary>
189			public static XmlNode secretRsaKey = XmlNode.FromFile("Private.RSA.key");
190			#endregion
191
192			#region Constructors
193			/// <summary>
194			/// Create encrypted test tcp server (using both AES and RSA)
195			/// </summary>
196			public TestEncryptedServer()
197				: base(ServerPort, BaseClient.NumberOfBasicMessageTypes,
198					aesPrivateKey, secretRsaKey)
199			{
200			}
201			#endregion
202
203			#region Methods (Private)
204
205			#region CreateClient
206			/// <summary>
207			/// Create TextClient
208			/// </summary>
209			protected override BaseClient CreateClient(Socket clientSocket)
210			{
211				return new TextClient(clientSocket, this);
212			}
213			#endregion
214
215			#region OnMessageReceived
216			/// <summary>
217			/// On message received, which is sent for every successful message
218			/// received other than Connect or Login.
219			/// </summary>
220			protected internal override void OnMessageReceived(BaseClient client,
221				byte messageType, BinaryReader data)
222			{
223				if (messageType == (byte)BasicMessageTypes.TextMessage)
224				{
225					string textString = data.ReadString();
226					Console.WriteLine("Received encrypted TextMessage on server from " +
227					                  "client=" + client + ": " +
228					                  textString.MaxStringLength(50,
229					                  	StringHelper.CutModes.EndWithDots) +
230					                  " (total length=" + textString.Length + ")");
231				}
232				else
233				{
234					Console.WriteLine("Received unknown encrypted message type=" +
235					                  messageType + " on server from client=" + client);
236				}
237			}
238			#endregion
239
240			#region OnClientLogin
241			/// <summary>
242			/// This method is called for every client that successfully connected
243			/// and is logged in now with some user data.
244			/// </summary>
245			protected override bool OnClientLogin(BaseClient client,
246				BinaryReader data)
247			{
248				base.OnClientLogin(client, data);
249				Console.WriteLine("TestEncryptedServer.OnClientLogin " + client);
250				return true;
251			}
252			#endregion
253
254			#region OnClientDisconnected
255			/// <summary>
256			/// This method is called for every client disconnect.
257			/// </summary>
258			protected override void OnClientDisconnected(BaseClient client)
259			{
260				Console.WriteLine("TestEncryptedServer.OnClientDisconnected " + client);
261				base.OnClientDisconnected(client);
262			}
263			#endregion
264
265			#endregion
266		}
267		#endregion
268
269		#region TextServer
270		public class TextServer : BaseServer
271		{
272			#region Constants
273			/// <summary>
274			/// Listen for connections on port 12345
275			/// </summary>
276			public const int ServerPort = 12345;
277
278			// Note: Message Type 0 and 1 are reserved for Connect and Login!
279			public const byte TextMessageType = 2;
280
281			public const byte EmptyMessageType = 3;
282
283			public const byte StressTestMessageType = 4;
284
285			public const byte NumOfMessageTypes = 5;
286			#endregion
287
288			#region StressTestMessagesReceived (Public)
289			/// <summary>
290			/// Helper for the StressTestMessageType, will count how much data
291			/// we have received to make sure the StressTest below works fine.
292			/// </summary>
293			public int StressTestMessagesReceived;
294			#endregion
295
296			#region StressTestDataReceived (Public)
297			/// <summary>
298			/// Helper for the StressTestMessageType, will count how much data
299			/// we have received to make sure the StressTest below works fine.
300			/// </summary>
301			public int StressTestDataReceived;
302			#endregion
303
304			#region Constructors
305			/// <summary>
306			/// Create test tcp server
307			/// </summary>
308			public TextServer()
309				: base(ServerPort, NumOfMessageTypes)
310			{
311			}
312			#endregion
313
314			#region Methods (Private)
315
316			#region CreateClient
317			/// <summary>
318			/// Create TextClient
319			/// </summary>
320			protected override BaseClient CreateClient(Socket clientSocket)
321			{
322				return new TextClient(clientSocket, this);
323			}
324			#endregion
325
326			#region OnMessageReceived
327			/// <summary>
328			/// On message received method, which is called whenever this server
329			/// receives any message from clients (except for Connect and Login
330			/// messages, which are already handled by the BaseServer class).
331			/// </summary>
332			protected internal override void OnMessageReceived(BaseClient client,
333				byte messageType, BinaryReader data)
334			{
335				if (messageType == TextMessageType)
336				{
337					string textString = data.ReadString();
338					if (textString.Length > 200)
339					{
340						Log.Info("Received really big TextMessage on server from client=" +
341						         client + ": " + textString.MaxStringLength(30,
342						         	StringHelper.CutModes.EndWithDots) +
343						         " (total length=" + textString.Length + ")");
344					}
345					else
346					{
347						Log.Info("Received TextMessage on server from client=" +
348						         client + ": " + textString);
349					}
350				}
351				else if (messageType == EmptyMessageType)
352				{
353					Log.Info("EmptyMessageType received from client=" + client);
354				}
355				else if (messageType == StressTestMessageType)
356				{
357					// This lock is important for the StressTest to count up correctly!
358					lock (this)
359					{
360						StressTestMessagesReceived++;
361						StressTestDataReceived += (int)data.BaseStream.Length;
362					}
363				}
364				else
365				{
366					Log.Info("Received unknown message type=" + messageType +
367					         " on server from client=" + client);
368				}
369			}
370			#endregion
371
372			#region OnClientLogin
373			/// <summary>
374			/// This method is called for every client that successfully connects.
375			/// </summary>
376			protected override bool OnClientLogin(BaseClient client,
377				BinaryReader data)
378			{
379				base.OnClientLogin(client, data);
380				// This lock is important for the StressTest not to mess up the log!
381				lock (this)
382				{
383					Log.Info("TextServer.OnClientLogin " + client);
384				}
385				return true;
386			}
387			#endregion
388
389			#region OnClientDisconnected
390			/// <summary>
391			/// This method is called for every client disconnect.
392			/// </summary>
393			protected override void OnClientDisconnected(BaseClient client)
394			{
395				Log.Info("TextServer.OnClientDisconnected " + client);
396				base.OnClientDisconnected(client);
397			}
398			#endregion
399
400			#endregion
401		}
402		#endregion
403
404		#endregion
405
406		#region ConnectTcpSocket (LongRunning)
407		[Test, Category("LongRunning")]
408		public static void ConnectTcpSocket()
409		{
410			// First start the server we want to connect
411			using (BaseServer testServer = new TestTcpServer())
412			{
413				Assert.Equal(SocketHelper.LastConnectionError, "");
414				Socket socket = SocketHelper.ConnectTcpSocket("localhost",
415					TestTcpServer.ServerPort);
416				Assert.Equal(socket.RemoteEndPoint.ToString(),
417					"127.0.0.1:" + TestTcpServer.ServerPort);
418				socket.Dispose();
419			}
420		}
421		#endregion
422
423
424		#region StartServerAndConnect (LongRunning)
425		/// <summary>
426		/// Start server and connect. This will just test the server side, this
427		/// test will make no use of the Client class.
428		/// </summary>
429		[Test, Category("LongRunning")]
430		public static void StartServerAndConnect()
431		{
432			// Start server (listens in an extra thread, see above)
433			BaseServer testServer = new TestTcpServer();
434
435			// And connect (in this thread)!
436			// See Client.Tests for more useful examples.
437			Socket serverSocket = SocketHelper.ConnectTcpSocket(
438				"127.0.0.1", TestTcpServer.ServerPort);
439			Assert.True(serverSocket.Connected);
440
441			// We need to send out a Connect message first to the server, else he
442			// will disconnect us right away. First byte of the Connect message
443			// must be 0 to indicate we use no encryption.
444			MemoryStream connectData = new MemoryStream();
445			connectData.WriteByte(0);
446			SocketHelper.SendMessageBytes(serverSocket,
447				(byte)BasicMessageTypes.Connect,
448				connectData.ToArray(), false);
449			// Next send the Login message with the Username
450			SocketHelper.SendMessageBytes(serverSocket,
451				(byte)BasicMessageTypes.Login,
452				StringHelper.StringToBytes("TestClient"), false);
453
454			// Send out a simple text message
455			Console.WriteLine("Sending: Hi from StartServerAndConnect");
456			SocketHelper.SendMessageBytes(serverSocket,
457				(byte)BasicMessageTypes.TextMessage,
458				StringHelper.StringToBytes("Hi from StartServerAndConnect"), false);
459
460			// Wait a bit for server to receive and display data!
461			Thread.Sleep(500);
462
463			// Always close the tcp server after starting it!
464			testServer.Dispose();
465			serverSocket.Close();
466			Assert.False(serverSocket.Connected);
467		}
468		#endregion
469
470		#region StartEncryptedServerAndConnect (LongRunning)
471		/// <summary>
472		/// Start encrypted server and connect
473		/// </summary>
474		[Test, Category("LongRunning")]
475		public static void StartEncryptedServerAndConnect()
476		{
477			// Start server (listens in an extra thread, see above)
478			BaseServer testServer = new TestEncryptedServer();
479
480			// And connect (in this thread)!
481			// See Client.Tests for more useful examples.
482			Socket serverSocket = SocketHelper.ConnectTcpSocket(
483				"127.0.0.1", TestTcpServer.ServerPort);
484			Assert.True(serverSocket.Connected);
485
486			// We need to send out a Connect message first to the server, else he
487			// will disconnect us right away. First byte of the Connect message
488			// must be 2 to indicate we use AES and RSA encryption.
489			MemoryStream connectData = new MemoryStream();
490			connectData.WriteByte(2);
491			// Next send the RSA encrypted seed value.
492			AES clientAes = new AES(TestEncryptedServer.aesPrivateKey);
493			byte[] encryptedSeed = testServer.rsa.Encrypt(clientAes.Seed);
494			connectData.Write(encryptedSeed, 0, encryptedSeed.Length);
495			//no RSA: connectData.Write(clientAes.Seed, 0, clientAes.Seed.Length);
496			SocketHelper.SendMessageBytes(serverSocket,
497				(byte)BasicMessageTypes.Connect,
498				connectData.ToArray(), false);
499
500			// And finally send the username with the Login message
501			SocketHelper.SendMessageBytes(serverSocket,
502				(byte)BasicMessageTypes.Login,
503				StringHelper.StringToBytes("TestEncryptedClient"), false, clientAes);
504
505			// Send out a simple text message
506			Console.WriteLine("Sending: Hi from StartServerAndConnect");
507			SocketHelper.SendMessageBytes(serverSocket,
508				(byte)BasicMessageTypes.TextMessage,
509				StringHelper.StringToBytes("Hi from StartServerAndConnect"), false,
510				clientAes);
511
512			// Send a big message (to test compression)!
513			string bigEmptyString = new string(' ', 10000);
514			SocketHelper.SendMessageBytes(serverSocket,
515				(byte)BasicMessageTypes.TextMessage,
516				StringHelper.StringToBytes("Hi Server " + bigEmptyString), true,
517				clientAes);
518
519			// Wait a bit for server to receive and display data!
520			Thread.Sleep(500);
521
522			// Always close the tcp server after starting it!
523			testServer.Dispose();
524			serverSocket.Close();
525			Assert.False(serverSocket.Connected);
526		}
527		#endregion
528
529		#region SendBigCompressableMessages (LongRunning)
530		/// <summary>
531		/// Helper method to test the compression features of the networking
532		/// classes, which are especially useful when sending big data messages.
533		/// In this test a very big message (10 KB) that is easily compressible
534		/// is send out to the server to see if it all arrives nice and dandy.
535		/// </summary>
536		[Test, Category("LongRunning")]
537		public static void SendBigCompressableMessages()
538		{
539			// Start server (listens in an extra thread, see TcpServer)
540			BaseServer server = new TextServer();
541
542			// And connect (in this thread)!
543			BaseClient client = new TextClient();
544
545			// Send a message from the client to the server!
546			string bigEmptyString = new string(' ', 10000);
547			client.SendTextMessage("Hi Server " + bigEmptyString);
548
549			// Wait a bit until the client is connected!
550			Thread.Sleep(100);
551
552			// Always close the client and server!
553			client.Dispose();
554			server.Dispose();
555		}
556		#endregion
557
558		#region JustConnectAndDisconnectSockets (LongRunning)
559		/// <summary>
560		/// Connect and disconnect via sockets. We cannot really send or receive
561		/// any useful message data here because we have to go through the whole
562		/// connection and login process and without using the Client and Server
563		/// classes this is just too much work. See the other unit tests for that.
564		/// </summary>
565		[Test, Category("LongRunning")]
566		public static void JustConnectAndDisconnectSockets()
567		{
568			TcpListener listener =
569				new TcpListener(IPAddress.Any, TextServer.ServerPort);
570
571			// Run the server thread, must be in parallel to the client code below
572			ThreadHelper.Start(delegate
573			{
574				listener.Start();
575				// Wait for client to connect (see below), this blocks.
576				Socket client = listener.AcceptSocket();
577				Log.Info("Client connected: " +
578				         SocketHelper.WriteClientInfo(client));
579				BaseClient clientInfo = new TextClient(client, null);
580
581				// Time to receive some data (see below again)
582				SocketHelper.SetupReceiveCallback(clientInfo.Socket,
583					clientInfo.clientBufferData,
584					SocketHelper.OnReceivedDataAsyncCallback, clientInfo);
585				Thread.Sleep(300);
586
587				if (client.Connected)
588				{
589					Log.Info("Disconnecting client: " +
590					         SocketHelper.WriteClientInfo(client));
591				}
592				client.Close();
593				listener.Stop();
594			});
595
596			// On the client side we just connect
597			Socket serverSocket = SocketHelper.ConnectTcpSocket(
598				TextClient.TestServer, TextServer.ServerPort);
599			/*Note: This will produce a warning because we did not correctly connect,
600 * use the other unit tests instead!
601			// Send out a simple data package
602			Log.Info("Sending EmptyMessage");
603			SocketHelper.SendMessageBytes(serverSocket, TextServer.EmptyMessageType,
604				null, false);
605			// And send out something more complex!
606			Log.Info("Sending TextMessage: Hi from " +
607				"SendAndReceiveMessageData");
608			SocketHelper.SendMessageBytes(serverSocket, TextServer.TextMessageType,
609				StringHelper.StringToBytes("Hi from SendAndReceiveMessageData"),
610				false);
611*/
612			// Wait a bit for data to arrive
613			Thread.Sleep(300);
614
615			// And finally disconnect, the thread above should have displayed
616			// everything we sent by now.
617			serverSocket.Shutdown(SocketShutdown.Both);
618			serverSocket.Disconnect(false);
619		}
620		#endregion
621
622		#region ConnectToServer (LongRunning)
623		/// <summary>
624		/// Connect to server
625		/// </summary>
626		[Test, Category("LongRunning")]
627		public static void ConnectToServer()
628		{
629			// Start server (listens in an extra thread, see TcpServer)
630			BaseServer server = new TestTcpServer();
631
632			// And connect (in this thread)!
633			BaseClient client = new TextClient();
634
635			// Send a message from the client to the server!
636			client.SendTextMessage("Hi Server");
637
638			// Wait a bit until the client is connected!
639			Thread.Sleep(100);
640			// And also send a message from the server to all clients
641			server.SendTextToAllClients("Hi Minions");
642
643			// Wait a bit for server to receive and display data!
644			Thread.Sleep(500);
645
646			// Always close the tcp server after starting it!
647			client.Dispose();
648			server.Dispose();
649		}
650		#endregion
651
652		#region ConnectToServerShortDelay (LongRunning)
653		/// <summary>
654		/// Connect to server with a short delay. This means we are trying to
655		/// connect to a server when it is not there yet. However, after a short
656		/// while we will have a server and then the client should automatically
657		/// connect (well in time for the timeout to still work) :)
658		/// </summary>
659		[Test, Category("LongRunning")]
660		public static void ConnectToServerShortDelay()
661		{
662			// Connect to the non-existing server (warning might appear)!
663			BaseClient client = new TextClient();
664
665			// Even send a message from the client to the not-connected server!
666			client.SendTextMessage("Hi Server");
667
668			// Wait a short while (well in time for the timeout to still work
669			// on the first connection attempt above).
670			Thread.Sleep(250);
671
672			// Now start the server delayed (listens in an extra thread)
673			BaseServer server = new TextServer();
674
675			// Wait a bit until the client is connected!
676			Thread.Sleep(500);
677			// And also send a message from the server to all clients
678			server.SendTextToAllClients("Hi Minions");
679
680			// Wait a bit for server to receive and display data!
681			Thread.Sleep(500);
682
683			// Always close the tcp server after starting it!
684			client.Dispose();
685			server.Dispose();
686		}
687		#endregion
688
689		#region ConnectToServerLongDelay (LongRunning)
690		/// <summary>
691		/// Connect to server long delay (more than the timeout allows us to
692		/// wait). This means we are trying to connect to a server when it is
693		/// not there yet. However, after a while we will have a server and then
694		/// the client should automatically attempt to re-connect.
695		/// </summary>
696		[Test, Category("LongRunning")]
697		public static void ConnectToServerLongDelay()
698		{
699			// Connect to the non-existing server (warning might appear)!
700			BaseClient client = new TextClient();
701
702			// Even send a message from the client to the not-connected server!
703			client.SendTextMessage("Hi Server");
704
705			Console.WriteLine("Waiting 5 seconds without a real connection!");
706
707			// Wait a long while (more than the timeout = 750ms allow us).
708			// Note: 10000ms is about 1 loop of extra waiting and then connecting.
709			Thread.Sleep(5000);
710
711			// Now start the server delayed (listens in an extra thread)
712			BaseServer server = new TextServer();
713
714			// Note: Increase time to 10s to be save (works fine with 5+6s now).
715			Console.WriteLine("Server is now on, waiting for another 5 seconds " +
716			                  "for the client to connect (it will try every 1-3 seconds)!");
717
718			// Wait a bit until the client is connected, can take up to 10 seconds
719			Thread.Sleep(5000);
720			// And also send a message from the server to all clients
721			server.SendTextToAllClients("Hi Minions");
722
723			// Wait a bit for server to receive and display data!
724			Thread.Sleep(500);
725
726			// Always close the tcp server after starting it!
727			client.Dispose();
728			server.Dispose();
729		}
730		#endregion
731
732		#region StressTest (LongRunning)
733		/// <summary>
734		/// Stress test with many packages. Usually tested with 100-1000
735		/// iterations. Enable LOG_STUFF to see more details and what happens.
736		/// Note: Works also fine with millions of messages send out (averages
737		/// to 128 MB for 1 million messages because of 1+random(255) message
738		/// length), takes about 10 seconds. For 1-1000 messages it is always
739		/// about 3-6ms (not dependant on the number of messages, so this is
740		/// just the setup time). So 1 message needs less than 10ns to be send
741		/// out and received on average, usually less!
742		/// </summary>
743		[Test, Category("LongRunning")]
744		public static void StressTest()
745		{
746			// Use 100 clients, which each send out 100 messages that are 1-252 bytes
747			// long, which results in about 1.2 MB network data. What is slow here
748			// is the logging, so it is disabled for this stress test message type.
749			const int NumberOfClients = 100;
750			const int NumberOfMessages = 100;
751
752			// Send blocks between 0 and 250 bytes
753			byte[] dummyData = new byte[250];
754			for (int i = 0; i < dummyData.Length; i++)
755			{
756				dummyData[i] = (byte)i;
757			}
758
759			// Create the server (will also count how much data arrives there)
760			TextServer server = new TextServer();
761
762			// And all our clients
763			TextClient[] clients = new TextClient[NumberOfClients];
764			int totalMessageDataSent = 0;
765			for (int num = 0; num < NumberOfClients; num++)
766			{
767				clients[num] = new TextClient();
768				// For each of them send out all messages right away.
769				for (int i = 0; i < NumberOfMessages; i++)
770				{
771					byte[] thisData = dummyData.GetSubArray(0,
772						RandomHelper.RandomInt(dummyData.Length));
773					clients[num].Send(TextServer.StressTestMessageType,
774						new MemoryStream(thisData));
775					totalMessageDataSent += thisData.Length;
776				}
777			} // for
778
779			// Wait a bit for data to arrive
780			Console.WriteLine("Waiting for all data to arrive");
781
782			int numberMessagesToReceive = NumberOfMessages * NumberOfClients;
783			Stopwatch watch = new Stopwatch();
784			watch.Start();
785			while (server.StressTestMessagesReceived < numberMessagesToReceive &&
786			       watch.Elapsed.TotalSeconds < 5)
787			{
788				Log.Test("Received=" + server.StressTestMessagesReceived);
789				Thread.Sleep(100);
790			}
791
792			// And finally disconnect the server from all clients
793			server.Dispose();
794
795			Console.WriteLine("NumberOfMessages * NumberOfClients=" +
796			                  numberMessagesToReceive +
797			                  ", server.StressTestMessagesReceived=" +
798			                  server.StressTestMessagesReceived);
799			Console.WriteLine("totalMessageDataSent=" + totalMessageDataSent +
800			                  ", server.StressTestDataReceived=" +
801			                  server.StressTestDataReceived);
802
803			// Send and received byte data length must be equal!
804			Assert.Equal(totalMessageDataSent, server.StressTestDataReceived);
805		}
806		#endregion
807	}
808}