/
Program.cs
330 lines (290 loc) · 12.6 KB
/
Program.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
/*** Fill these lines with your complete information.
* Note: Incomplete information may result in FAIL.
* Mameber 1: Max van Oord
* Mameber 2: Joeri Huigsloot
* Std Number 1: 0966232
* Std Number 2:
* Class: INF2E
***/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
/* Note: If you are using .net core 2.1, install System.Text.Json (use NuGet). */
using System.Text.Json;
using System.Threading;
namespace SocketServer
{
public class ClientInfo
{
public string studentnr { get; set; }
public string classname { get; set; }
public int clientid { get; set; }
public string teamname { get; set; }
public string ip { get; set; }
public string secret { get; set; }
public string status { get; set; }
}
public class Message
{
public const string welcome = "WELCOME";
public const string stopCommunication = "COMC-STOP";
public const string statusEnd = "STAT-STOP";
public const string secret = "SECRET";
}
public class SequentialServer
{
public Socket listener; // listener is our server side Socket object where we listen on for client connections
public IPEndPoint localEndPoint; // localEndPoint is a network binding between IP and PORT where our server listens on
public IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); // we define our IP address to be local
public readonly int portNumber = 11111; // we define a port number
public String results = "";
public LinkedList<ClientInfo> clients = new LinkedList<ClientInfo>(); // we define a list which holds all info about connected clients
private Boolean stopCond = false;
private int processingTime = 1000;
private int listeningQueueSize = 5;
public void prepareServer()
{
byte[] bytes = new Byte[1024]; // we use bytes as our max size of incomming receive data
String data = null;
int numByte = 0;
string replyMsg = "";
bool stop;
try
{
Console.WriteLine("[Server] is ready to start ...");
// Establish the local endpoint
localEndPoint = new IPEndPoint(ipAddress, portNumber);
listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Console.Out.WriteLine("[Server] A socket is established ...");
// associate a network address to the Server Socket. All clients must know this address
listener.Bind(localEndPoint);
// This is a non-blocking listen with max number of pending requests
listener.Listen(listeningQueueSize);
while (true)
{
Console.WriteLine("Waiting connection ... ");
// Suspend while waiting for incoming connection
Socket connection = listener.Accept(); // at this point the program is stuck on waiting
this.sendReply(connection, Message.welcome);
stop = false;
while (!stop)
{
numByte = connection.Receive(bytes); // numByte is the encoded received message
data = Encoding.ASCII.GetString(bytes, 0, numByte); // data holds the decoded received message
replyMsg = processMessage(data);
if (replyMsg.Equals(Message.stopCommunication))
{
stop = true;
break;
}
else
this.sendReply(connection, replyMsg);
}
}
}
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
}
}
public void handleClient(Socket con)
{
}
public string processMessage(String msg)
{
Thread.Sleep(processingTime);
Console.WriteLine("[Server] received from the client -> {0} ", msg);
string replyMsg = "";
try
{
switch (msg)
{
case Message.stopCommunication:
replyMsg = Message.stopCommunication;
break;
default:
ClientInfo c = JsonSerializer.Deserialize<ClientInfo>(msg.ToString());
clients.AddLast(c);
if (c.clientid == -1)
{
stopCond = true;
exportResults();
}
c.secret = c.studentnr + Message.secret;
c.status = Message.statusEnd;
replyMsg = JsonSerializer.Serialize<ClientInfo>(c);
break;
}
}
catch (Exception e)
{
Console.Out.WriteLine("[Server] processMessage {0}", e.Message);
}
return replyMsg;
}
public void sendReply(Socket connection, string msg)
{
byte[] encodedMsg = Encoding.ASCII.GetBytes(msg);
connection.Send(encodedMsg);
}
public void exportResults()
{
if (stopCond)
{
this.printClients();
}
}
public void printClients()
{
string delimiter = " , ";
Console.Out.WriteLine("[Server] This is the list of clients communicated");
foreach (ClientInfo c in clients)
{
Console.WriteLine(c.classname + delimiter + c.studentnr + delimiter + c.clientid.ToString());
}
Console.Out.WriteLine("[Server] Number of handled clients: {0}", clients.Count);
clients.Clear();
stopCond = false;
}
}
public class ConcurrentServer
{
public Socket listener; // listener is our server side Socket object where we listen on for client connections
public IPEndPoint localEndPoint; // localEndPoint is a network binding between IP and PORT where our server listens on
public IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
public readonly int portNumber = 11111;
public List<Thread> threadList = new List<Thread>(); // a collection of all running threads in our program
public LinkedList<ClientInfo> clients = new LinkedList<ClientInfo>(); // a list which holds all info about connected clients
public Boolean stopCond = false;
private int processingTime = 1000;
private int listeningQueueSize = 250;
public void prepareServer() {
try
{
Console.WriteLine("[Server] is ready to start ...");
// Establish the local endpoint
localEndPoint = new IPEndPoint(ipAddress, portNumber);
listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Console.Out.WriteLine("[Server] A socket is established ...");
// associate a network address to the Server Socket. All clients must know this address
listener.Bind(localEndPoint);
// This is a non-blocking listen with max number of pending requests
listener.Listen(listeningQueueSize);
while (true) // main thread is only accepting connections and making threads
{
Socket connection = listener.Accept(); // main thread accepting a client's connection
threadList.Add(new Thread(() => handleClient(connection))); // adding a new thread to our program which is going to handle the connection
if (threadList.Count() > 0){
threadList.Last().Start(); // starting the added thread
}
}
}
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
}
}
public void handleClient(Socket connection)
// this method is running for each connected client on a different thread
{
byte[] bytes = new Byte[1024];
String data = null;
int numByte = 0;
string replyMsg = "";
bool run = true;
this.sendReply(connection, Message.welcome); // first we need to send the client a welcome message
while (run) // then we need to start checking for messages in a loop
{
numByte = connection.Receive(bytes); // receiving a message from client's connection
data = Encoding.ASCII.GetString(bytes, 0, numByte);
replyMsg = processMessage(data); // we generate a reply message with the method processMessage
if (replyMsg.Equals(Message.stopCommunication)) // if the client returns with a 'stop' message we close the connection
{
run = false;
break;
}
else
{
this.sendReply(connection, replyMsg); // otherwise we reply to the client with a secret + status
}
}
}
public string processMessage(String msg)
// argument: incomming message from a client
// return: message to sent back to client
{
//Thread.Sleep(processingTime);
Console.WriteLine("[Server] received from the client -> {0} ", msg);
string replyMsg = "";
try
{
switch (msg)
{
case Message.stopCommunication: // if the message is a "COMC-STOP" we close the connection in HandleClient()
replyMsg = Message.stopCommunication;
break;
default:
ClientInfo c = JsonSerializer.Deserialize<ClientInfo>(msg.ToString()); // converting client's message to a ClientInfo object
clients.AddLast(c);
if (c.clientid == -1)
{
printClients(); // when the last client connected we print info about all connected clients
}
c.secret = c.studentnr + Message.secret;
c.status = Message.statusEnd;
replyMsg = JsonSerializer.Serialize<ClientInfo>(c);
break;
}
}
catch (Exception e)
{
Console.Out.WriteLine("[Server] processMessage {0}", e.Message);
}
return replyMsg;
}
public void sendReply(Socket connection, string msg)
{
byte[] encodedMsg = Encoding.ASCII.GetBytes(msg);
connection.Send(encodedMsg);
}
public void printClients()
{
string delimiter = " , ";
Console.Out.WriteLine("[Server] This is the list of clients communicated");
foreach (ClientInfo c in clients)
{
Console.WriteLine(c.classname + delimiter + c.studentnr + delimiter + c.clientid.ToString());
}
Console.Out.WriteLine("[Server] Number of handled clients: {0}", clients.Count);
}
}
public class ServerSimulator
{
public static void sequentialRun()
{
Console.Out.WriteLine("[Server] A sample server, sequential version ...");
SequentialServer server = new SequentialServer();
server.prepareServer();
}
public static void concurrentRun()
{
Console.Out.WriteLine("[Server] A sample server, concurrent version ...");
ConcurrentServer server = new ConcurrentServer();
server.prepareServer();
}
}
class Program
{
// Main Method
static void Main(string[] args)
{
Console.Clear();
//ServerSimulator.sequentialRun();
// todo: uncomment this when the solution is ready.
ServerSimulator.concurrentRun();
}
}
}