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