forked from PetrerW/TSST-Project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClientApplication.cs
510 lines (449 loc) · 27.5 KB
/
ClientApplication.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
using NetworkingTools;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ClientNode
{
/// <summary>
/// Główna klasa związana z obsługą aplikacji klienckiej. Odpalona zostaje po zakończeniu działania okienka klasy: <class>ClientNode.StartClientApplication.cs</class>.
/// </summary>
public partial class ClientApplication : Form
{
//Zmienna, która posłuży do nasłuchiwania nadchodzących wiadomości od strony chmury
public static SocketListener sl = new SocketListener();
//Zmienna, która posłuży do wysyłania wiadomości od użytkownika do chmury
public static SocketSending sS = new SocketSending();
//Token, który posłuży do zamknięcia sesji
public static CancellationTokenSource _cts = new CancellationTokenSource();
//Obiekt klasy ClientApplication, posłuży do odwołań do różnych pól klasy (głównie obsługa elementów związanych z WindowsForm)
public ClientApplication _ClientApplication;
//Gniazdo obsługujące wysyłanie wiadomosci przez połączenie TCP
public Socket send;
//Gniazdo obsługujące odbieranie wiadomości przez połączenie TCP
public Socket socket;
//Zmienna informująca o tym, czy przycisk odpowiedzialny za wysyłanie wiadomości został naciśnięty
bool buttonSendClicked = false;
//Zmienna informująca o tym, czy przycisk odpowiedzialny za wysyłanie wiadomości został naciśnięty
bool buttonSendRandomClicked = false;
//Zmienna informująca o tym, czy przycisk odpowiedzialny za zakończenie wysyłania wiadomości został naciśnięty
bool buttonStopSendingClicked = false;
//Zmienna informujaca o tym, czy przycisk odpowiedzialny za połączenie z chmurą został wciśnięty
bool buttonConnectToCloudClicked = false;
//Task, na nim uruchomione będzie wysyłanie wiadomości
Task t;
//IP aplikacji klienckiej dołączającej się do sieci
string ClientIP;
//Port apliakcji klienckiej dołączającej się do sieci
string ClientPort;
//Port na którym aplikacja kliencka będzie łączyła się z chmura
string CloudPort;
/// <summary>
/// Lista zawierająca IP wszystkich aplikacji klieckich
/// <para>IP aplikacji przechowywane są w postaci stringów</para>
/// </summary>
List<string> clientsiplist;
/// <summary>
/// Lista zawierająca IP wszystkich połączeń z chmurą
/// <para>IP chmury przechowywane są w postaci stringów</para>
/// </summary>
List<string> cloudsiplist;
//Paczka która będzie wysyłana za pośrednictwem sieci
Package EONpackage;
/// <summary>
/// Konstruktor obiektu z klasy ClientApplication
/// </summary>
/// <param name="ClientIP">IP aplikacji klienckiej</param>
/// <param name="ClientPort">Port aplikacji klienckiej</param>
/// <param name="CloudPort">Port chmury</param>
public ClientApplication(string ClientIP, string ClientPort, string CloudPort)
{
//Ustawienie CultureInfo na en-US spowoduje wyświetlanie się wyłapanych Exceptions w języku angielskim
// Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
//Zainicjowanie okna WindowsForm
InitializeComponent();
//Przypisanie referencji na dany obiekt
_ClientApplication = this;
//Przypisanie obiektowi IP aplikacji klienta, które zostało przekazane przez konstruktor z okna poziomu StartClientApplication
this.ClientIP = ClientIP;
//Przypisanie obiektowi Portu aplikacji klienta, które zostało przekazane przez konstruktor z okna poziomu StartClientApplication
this.ClientPort = ClientPort;
//Przypisanie obiektowi Portu chmury, które zostało przekazane przez konstruktor z okna poziomu StartClientApplication
this.CloudPort = CloudPort;
//Inicjalizacja listy zawierajacej ip klientów
clientsiplist = new List<string>();
//Inicjalizacja listy zawierajacej ip chmury, przez które będą łączyć się apliakcje klienckie
cloudsiplist = new List<string>();
//Odczytywanie z pliku konfiguracyjnego
for (int i = 0; i < 3; i++)
{
//String niezbędny do porównania IP, a później odpowiedniego nazwania aplikacji
string temp = "ClientIP" + i;
//Dodawanie odczytanych IP aplikacjji klienckich do listy
cloudsiplist.Add(ConfigurationManager.AppSettings[i + 3]);
//Sprawdzenie czy wpisane IP w StartClientApplication jest takie samo IP w pliku konfiguracyjnym
if (ConfigurationManager.AppSettings[i] == _ClientApplication.ClientIP)
{
//Nadanie nazwy aplikacji - zgodnie z odczytanym IP z pliku konfiguracyjnego
_ClientApplication.Text = ConfigurationManager.AppSettings[temp];
//Dodanie IP klienckiej aplikacji do list
clientsiplist.Add(ConfigurationManager.AppSettings[i]);
}
else
{
//Dodanie IP klienckiej aplikacji do listy
clientsiplist.Add(ConfigurationManager.AppSettings[i]);
//Dodanie IP aplikacji kliencjiej do listy
_ClientApplication.comboBoxClients.Items.Add(ConfigurationManager.AppSettings[temp]);
}
}
}
/// <summary>
/// Funkcja uruchamiana w momencie naciśnięcia przycisku wysyłania
/// </summary>
/// <param name="sender">Obiekt, który odpowiedzialny jest za wysłanie eventu</param>
/// <param name="e">Otrzymany event po naciśnięciu przycisku</param>
private void buttonSend_Click(object sender, EventArgs e)
{
//Cel wysyłania naszej wiadomości, pobrany z comboBoxa
string destination = comboBoxClients.SelectedItem.ToString();
//Ustawienie wartości true pozwala na zatrzymanie wysyłania
buttonStopSendingClicked = false;
if (buttonSendClicked == false)
{
t = Task.Run(async () =>
{
//Pętla odpowiedzialna za ciągłe wysyłanie wiadomości do wyznaczonego klienta
while (buttonStopSendingClicked != true)
{
short frameID = (short)(new Random()).Next(0, short.MaxValue);
//Pobranie wiadomości
string message = textBoxMessage.Text;
short messageLength = (short)message.Length;
byte[] bytemessage;
List<byte[]> packageList = new List<byte[]>();
if (messageLength > Package.usableInfoMaxLength)
{
double numberOfPackages = (Math.Ceiling((double)messageLength / Package.usableInfoMaxLength));
short tmpLength = Convert.ToInt16(messageLength - (short)((short)(numberOfPackages - 1) * Package.usableInfoMaxLength));
for (int i = 0; i < numberOfPackages; i++)
{
if (i < numberOfPackages - 1)
{
bytemessage = null;
EONpackage = new Package(message.Substring(i * Package.usableInfoMaxLength, Package.usableInfoMaxLength),
1, destination, _ClientApplication.ClientIP, Convert.ToInt16(Package.usableInfoMaxLength),
Convert.ToInt16(i + 1), (short)(-1), (short)(-1), (short)(-1), (short)(-1), frameID, Convert.ToInt16(numberOfPackages));
bytemessage = EONpackage.toBytes();
}
else
{
bytemessage = null;
EONpackage = new Package(message.Substring(i * Package.usableInfoMaxLength, messageLength - i * Package.usableInfoMaxLength),
1, destination, _ClientApplication.ClientIP, tmpLength, Convert.ToInt16(i + 1),
(short)(-1), (short)(-1), (short)(-1), (short)(-1), frameID, Convert.ToInt16(numberOfPackages));
bytemessage = EONpackage.toBytes();
}
packageList.Add(bytemessage);
}
if (send.Connected)
{
for (int i = 0; i < packageList.Count(); i++)
{
string timestamp2 = Timestamp.generateTimestamp();
//Wysłanie wiadomości (tablicy bajtów) za pośrednictwem gniazda
sS.SendingPackageBytes(send, packageList[i]);
_ClientApplication.updateLogTextBox("[" + timestamp2 + "] == SENDING PACKAGE number: " + (i + 1) + " == ");
var wait = await Task.Run(async () =>
{
Stopwatch sw = Stopwatch.StartNew();
await Task.Delay(10);
sw.Stop();
return sw.ElapsedMilliseconds;
});
}
}
//Stworzenie znacznika czasowego
string timestamp = Timestamp.generateTimestamp();
_ClientApplication.updateLogTextBox("[" + timestamp + "] == SENDING MESSAGE in " + numberOfPackages + " packages == " + " D_ClientIP " + destination);
}
else
{
//Stworzenie wysyłanej paczki
bytemessage = null;
EONpackage = new Package(message, 1, destination, _ClientApplication.ClientIP, messageLength, Convert.ToInt16(1), (short)(-1), (short)(-1), (short)(-1),
(short)(-1), frameID, 1);
bytemessage = EONpackage.toBytes();
//Stworzenie znacznika czasowego
string timestamp = Timestamp.generateTimestamp();
//Zamiana paczki na tablicę bajtów
if (send.Connected)
{
//Wysłanie wiadomości (tablicy bajtów) za pośrednictwem gniazda
sS.SendingPackageBytes(send, bytemessage);
//Zaktualizowanie LogEventTextBoxa
_ClientApplication.updateLogTextBox("[" + timestamp + "] == SENDING MESSAGE == D_ClientIP " + destination);
}
}
//Task, który służy wprowadzeniu opóźnienia między kolejnymi wysłanymi pakietami
var delay = await Task.Run(async () =>
{
Stopwatch sw = Stopwatch.StartNew();
await Task.Delay(3000);
sw.Stop();
return sw.ElapsedMilliseconds;
});
}
});
}
//Zablokowanie podwójnego naciśnięcia przycisku wysyłania
buttonSendClicked = true;
}
/// <summary>
/// Funkcja uruchamiana w momencie naciśnięcia przycisku połączenie z chmura
/// </summary>
/// <param name="sender">Obiekt, który odpowiedzialny jest za wysłanie eventu</param>
/// <param name="e">Otrzymany event po naciśnięciu przycisku</param>
private void buttonConnectToCloud_Click(object sender, EventArgs e)
{
if (buttonConnectToCloudClicked == false)
{
buttonConnectToCloud.Enabled = false;
buttonConnectToCloudClicked = true;
//Pobranie indeksu na którym w liście znajduje się IP naszej klienckiej aplikacji
int cloudipindex = clientsiplist.IndexOf(_ClientApplication.ClientIP);
//Pobranie IP chmury z listy
string cloudIP = cloudsiplist[cloudipindex];
try
{
//Próba połączenia się z IP chmury, z którego bedziemy nasłuchiwali wiadomości
send = sS.ConnectToEndPoint(cloudIP);
if (send.Connected)
{
//Uruchomienie nasłuchiwania w aplikacji klienckiej
socket = sl.ListenAsync(_ClientApplication.ClientIP);
Task.Run(() =>
{
while (true)
{
byte[] messagebytes;
List<byte[]> packages = new List<byte[]>();
//Zamienienie odebranej wiadomości na tablicę bajtów
messagebytes = sl.ProcessRecivedBytes(socket);
//Utowrzenie znacznika czasowego
int numberOfPackages = 1;
string timestamp2 = Timestamp.generateTimestamp();
string message = null;
short howManyPackages = Package.extractHowManyPackages(messagebytes);
short frameID = Package.extractID(messagebytes);
packages.Add(messagebytes);
if (howManyPackages >= 2)
{
for (int i = 1; i < howManyPackages; i++)
{
messagebytes = null;
messagebytes = sl.ProcessRecivedBytes2(socket);
if (messagebytes == null)
break;
packages.Add(messagebytes);
numberOfPackages++;
}
//Utowrzenie znacznika czasowego
string timestamp = Timestamp.generateTimestamp();
//Sortowanie paczek, jakby przy odbiorze paczki zamieniły się miejscami
for (int i = 0; i < packages.Count - 1; i++)
{
if (Package.extractPackageNumber(packages[i]) > Package.extractPackageNumber(packages[i + 1]))
{
byte[] tmp = packages[i];
packages[i] = packages[i + 1];
packages[i + 1] = tmp;
}
}
for (int i = 0; i < packages.Count(); i++)
{
message = message + Package.extractUsableMessage(packages[i], Package.extractUsableInfoLength(packages[i]));
}
//Odpakowanie adresy nadawcy z otrzymanej wiadomości
string sourceIp = Package.exctractSourceIP(messagebytes).ToString();
_ClientApplication.updateReceivedMessageTextBox(sourceIp + ": " + message);
_ClientApplication.updateReceivedMessageTextBox("\r\n");
_ClientApplication.updateLogTextBox("[" + timestamp + "] == RECEIVED MESSAGE in " + numberOfPackages + " packages from " + howManyPackages + " == S_ClientIP: " + sourceIp);
message = null;
messagebytes = null;
packages = null;
}
else
{
//Odpakowanie adresy nadawcy z otrzymanej wiadomości
string sourceIp = Package.exctractSourceIP(messagebytes).ToString();
//Stworzenie wiadomości, która zostanie wyświetlona na ekranie - odpakowanie treści wiadomości z paczki
string message2 = sourceIp + ": " + Package.extractUsableMessage(messagebytes, Package.extractUsableInfoLength(messagebytes));
//Pojawienie się informacji o otrzymaniu wiadomości
_ClientApplication.updateLogTextBox("[" + timestamp2 + "] == RECEIVED MESSAGE == S_ClientIP: " + sourceIp);
//Zauktualizowanie wiadomości w polu ReceivedMessage
_ClientApplication.updateReceivedMessageTextBox(message2);
_ClientApplication.updateReceivedMessageTextBox("\r\n");
message2 = null;
messagebytes = null;
}
}
});
}
else
{
throw new NullReferenceException();
buttonConnectToCloud.Enabled = true;
buttonConnectToCloudClicked = false;
}
}
catch (Exception err)
{
MessageBox.Show("Unable to connect to the Network Host!", "Attention!");
}
}
}
/// <summary>
/// Funkcja uruchamiana w momencie naciśnięcia przycisku odpowiedzialnego za wysyłanie wiadomości o losowej długości
/// </summary>
/// <param name="sender">Obiekt, który odpowiedzialny jest za wysłanie eventu</param>
/// <param name="e">Otrzymany event po naciśnięciu przycisku</param>
private void buttonDifferentMessages_Click(object sender, EventArgs e)
{
if (comboBoxClients.SelectedItem != null)
{
//Pobranie celu do którego wysłana zostanie wiadomość
string destination = comboBoxClients.SelectedItem.ToString();
//Zmiana ustawienia przycisku kończącego wysyłanie
buttonStopSendingClicked = false;
if (buttonSendRandomClicked == false)
{
t = Task.Run(async () =>
{
while (buttonStopSendingClicked != true)
{
short frameID = (short)(new Random()).Next(0, short.MaxValue);
string message = null;
//Wygnenerowanie losowej wiadomości o maksymalnej długości
message = RandomMessageGenerator.generateRandomMessage(37);
//Pobranie wiadomości
short messageLength = (short)message.Length;
byte[] bytemessage;
List<byte[]> packageList = new List<byte[]>();
if (messageLength > Package.usableInfoMaxLength)
{
double numberOfPackages = (Math.Ceiling((double)messageLength / Package.usableInfoMaxLength));
short tmpLength = Convert.ToInt16(messageLength - (short)((short)(numberOfPackages - 1) * Package.usableInfoMaxLength));
for (int i = 0; i < numberOfPackages; i++)
{
if (i < numberOfPackages - 1)
{
bytemessage = null;
EONpackage = new Package(message.Substring(i * Package.usableInfoMaxLength, Package.usableInfoMaxLength), 1, destination, _ClientApplication.ClientIP,
Convert.ToInt16(Package.usableInfoMaxLength), Convert.ToInt16(i + 1), (short)-1, (short)(-1), (short)(-1), (short)(-1), frameID, Convert.ToInt16(numberOfPackages));
bytemessage = EONpackage.toBytes();
}
else
{
bytemessage = null;
EONpackage = new Package(message.Substring(i * Package.usableInfoMaxLength, messageLength - i * Package.usableInfoMaxLength), 1,
destination, _ClientApplication.ClientIP, tmpLength, Convert.ToInt16(i + 1), (short)-1, (short)(-1), (short)(-1), (short)(-1), frameID, Convert.ToInt16(numberOfPackages));
bytemessage = EONpackage.toBytes();
}
packageList.Add(bytemessage);
}
if (send.Connected)
{
for (int i = 0; i < packageList.Count(); i++)
{
string timestamp2 = Timestamp.generateTimestamp();
//Wysłanie wiadomości (tablicy bajtów) za pośrednictwem gniazda
sS.SendingPackageBytes(send, packageList[i]);
// _ClientApplication.updateLogTextBox("[" + timestamp2 + "] == SENDING PACKAGE number: " + (i + 1) + " == ");
var wait = await Task.Run(async () =>
{
Stopwatch sw = Stopwatch.StartNew();
await Task.Delay(10);
sw.Stop();
return sw.ElapsedMilliseconds;
});
}
}
//Stworzenie znacznika czasowego
string timestamp = Timestamp.generateTimestamp();
_ClientApplication.updateLogTextBox("[" + timestamp + "] == SENDING MESSAGE in " + numberOfPackages + " packages == " + " D_ClientIP " + destination);
}
else
{
//Stworzenie wysyłanej paczki
bytemessage = null;
EONpackage = new Package(message, 1, destination, _ClientApplication.ClientIP, messageLength, Convert.ToInt16(1), (short)(-1),
(short)(-1), (short)(-1), (short)(-1), frameID, 1);
bytemessage = EONpackage.toBytes();
//Stworzenie znacznika czasowego
string timestamp = Timestamp.generateTimestamp();
//Zamiana paczki na tablicę bajtów
if (send.Connected)
{
//Wysłanie wiadomości (tablicy bajtów) za pośrednictwem gniazda
sS.SendingPackageBytes(send, bytemessage);
//Zaktualizowanie LogEventTextBoxa
_ClientApplication.updateLogTextBox("[" + timestamp + "] == SENDING MESSAGE == D_ClientIP " + destination);
}
}
//Task, który służy wprowadzeniu opóźnienia między kolejnymi wysłanymi pakietami
var delay = await Task.Run(async () =>
{
Stopwatch sw = Stopwatch.StartNew();
await Task.Delay(3000);
sw.Stop();
return sw.ElapsedMilliseconds;
});
}
});
}
//Zablokowanie podwójnego naciśnięcia przycisku wysyłania
buttonSendRandomClicked = true;
}
}
/// <summary>
/// Funkcja uruchamiana w momencie naciśnięcia przycisku odpowiedzialnego za zatrzymanie wysyłania
/// </summary>
/// <param name="sender">Obiekt, który odpowiedzialny jest za wysłanie eventu</param>
/// <param name="e">Otrzymany event po naciśnięciu przycisku</param>
private void buttonStopSending_Click(object sender, EventArgs e)
{
buttonSendClicked = false;
buttonSendRandomClicked = false;
buttonStopSendingClicked = true;
}
/// <summary>
/// Funkcja odpowiedzialna za aktualizowanie pola LogEvent - służy przesyłaniu wiadomości miedzy wątkami
/// </summary>
/// <param name="message">Wiadomość o którą zostanie zaktualizowane pole LogEvent</param>
public void updateLogTextBox(string message)
{
_ClientApplication.textBoxLog.Invoke(new Action(delegate ()
{
_ClientApplication.textBoxLog.AppendText(message + "\r\n");
}));
}
/// <summary>
/// Funkcja odpowiedzialna za aktualizowanie pola ReceivedMessage - służy przesyłaniu wiadomości miedzy wątkami
/// </summary>
/// <param name="message">Wiadomość o którą zostanie zaktualizowane pole ReceivedMessage</param>
public void updateReceivedMessageTextBox(string message)
{
_ClientApplication.textBoxReceived.Invoke(new Action(delegate ()
{
_ClientApplication.textBoxReceived.AppendText(message);
}));
}
}
}