- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTCPServerMT.java
More file actions
Latest commit
364 lines (335 loc) · 11.6 KB
/
Copy pathTCPServerMT.java
File metadata and controls
364 lines (335 loc) · 11.6 KB
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
/*
Name: Joshua Kuiper
Project Description:
This is a multithreaded client/server program.
Many clients can connect to one server, and contents of their chat in a chat room
is stored with in a chat file which is created if a user joins an empty chat room,
displays to all users when they join, and deletes if they're the last one to leave.
Programmer: COSC 439/522, F '21
Multi-threaded Server program
File name: TCPServerMT.java
When you run this program, you must give the service port
number as a command line argument. For example,
java TCPServerMT -p 20600 -g 1019 -n 1823
*/
importjava.net.*;
importjava.util.*;
importjava.io.*;
importjava.nio.charset.StandardCharsets;
importjava.util.Arrays;
publicclassTCPServerMT {
privateServerSocketservSock;
//ArrayList of handlers to be used in file and output to server / client screens
privateArrayList<ClientHandler> myHandlers;
FilemyFile;
PrintWriterwriter;
intuserCount = 0;
intprivateKey = (int)((Math.random() * (201 - 100)) + 100);
staticStringgee = "";
staticStringnee = "";
//Creates ability to create handlers and server socket to be used by everyone
publicjku_TCPServerMT(ServerSocketservSock) {
this.servSock = servSock;
myHandlers = newArrayList<ClientHandler>();
}
publicstaticvoidmain(String[] args) throwsException {
System.out.println("Opening port...\n");
//Default declaration if portNumber isn't entered
StringportNumber = "20600";
Stringg = "1019";
Stringn = "1823";
gee = g;
nee = n;
try{
//Accepts command line arguments to change portNumber
for(inti = 0; i < args.length; i++) {
if(args[i] != null) {
if(args[i].equals("-p")) {
portNumber = args[i+1];
}
elseif(args[i].equals("-g")) {
g = args[i+1];
gee = g;
}
elseif(args[i].equals("-n")) {
n = args[i+1];
nee = n;
}
/*
I know you said we need to do this but if you uncomment this,
The only way for it to work is by not giving any arguments.
It always complains and I couldn't figure it out...
else{
System.out.println("Invalid Input!");
System.exit(0);
}
*/
}
}
}catch(Exceptione){
System.out.println("Unable to attach to port!");
System.exit(1);
}
//Creates a new instance with server socket then adds the new handler
//Removes the need for the void run() method which would do this before
//It does the same thing as the old run() in less lines and it's cleaner
newjku_TCPServerMT(newServerSocket(Integer.parseInt(portNumber))).getConnections();
}
//Creates the new handler, starts it, and adds the handler to the ArrayList of handlers
publicvoidgetConnections() throwsIOException {
while(true){
ClientHandlernewHandler = newClientHandler(servSock.accept(), this);
newHandler.start();
addNewClient(newHandler);
}
}
//This is the method that sends the message out to all clients, except itself
publicsynchronizedvoidthreadedOut(ClientHandlersender, Stringmessage){
//Gets the generated key
longgenKey = power(Long.parseLong(gee), privateKey, Long.parseLong(nee));
//Secret key for Server
longsecretKey = power(genKey, privateKey, Long.parseLong(nee));
for (ClientHandlerhandlerList : myHandlers) {
if (handlerList != sender) {
message = encrypt(message, (int)secretKey);
handlerList.out.println(message);
}
}
}
//Adds a new client handler to ArrayList
publicsynchronizedvoidaddNewClient(ClientHandlernewHandler){
myHandlers.add(newHandler);
}
//Removes handler from the ArrayList
publicsynchronizedvoidremoveOldClient(ClientHandlernewHandler){
myHandlers.remove(newHandler);
}
//Synchronized write to file.
//Sure it's not efficient, but it works!
publicsynchronizedvoidwriteToFile(Stringmessage){
//The extra println is because it was bugging when I was reading it. It works this way idk.
writer.println(message + "\n");
writer.flush();
}
publicsynchronizedvoidreadFromFile(PrintWriterout){
try{
BufferedReaderfileReader = newBufferedReader(newFileReader(myFile));
StringcurrLine;
while ((currLine = fileReader.readLine()) != null){
out.println(currLine);
}
}catch(Exceptione){}
}
//Creates new file when needed
publicvoidcreateFile(){
if(userCount == 0){
myFile = newFile("jku_chat.txt");
try{
writer = newPrintWriter(myFile);
}catch(Exceptione){};
}
}
//Deletes file when needed
publicvoiddeleteFile(){
myFile.delete();
}
//Client Handler Class
publicclassClientHandlerextendsThread {
//Socket and Server object to send output to all clients
privateSocketclient;
privatejku_TCPServerMTserver;
//Input & Output to console
privateBufferedReaderin;
privatePrintWriterout;
//Makes sure it's only using THIS handler
publicClientHandler(Socketclient, jku_TCPServerMTserver) {
this.client = client;
this.server = server;
}
publicvoidrun() {
intnumMessages = -1;
server.createFile();
userCount = userCount + 1;
try {
//Set up input and output streams for socket
in = newBufferedReader(newInputStreamReader(client.getInputStream()));
out = newPrintWriter(client.getOutputStream(),true);
//Gets username based on first line of input.
Stringusername = "";
if(numMessages <= -1){
username = in.readLine();
numMessages = 0;
}
longgenKey = power(Long.parseLong(gee), privateKey, Long.parseLong(nee));
longsecretKey = power(genKey, privateKey, Long.parseLong(nee));
//Prints the username + host you're at
Stringhost = InetAddress.getLocalHost().getHostName();
System.out.println(username + " has established a connection to " + host);
server.writeToFile(gee + " " + nee + " " + username + " has established a connection to " + host);
System.out.println("Handshake complete. G: " + gee + " N: " + nee + " Session Key: " + secretKey + " Byte Pad: "
+ convertAsciiToBinary(convertToAscii(String.valueOf(privateKey))).substring(8, 16));
//Reads from file
server.readFromFile(out);
//Reads in the message, outputs to screen, increments number of messages,
//then ouputs to all other clients.
Stringmessage;
while ((message = in.readLine()) != null) {
if(message.equals("DONE")){
break;
}
//Prints all the messages and writes the messages to file.
StringnewMessage = username + ": " + message;
System.out.println(newMessage);
numMessages++;
server.writeToFile(newMessage);
server.threadedOut(this, newMessage);
}
//Sends message if client leaves the chat room
server.threadedOut(this, username + " Left the chat room.");
server.writeToFile(username + " Left the chat room.");
userCount = userCount - 1;
if(userCount == 0){
server.deleteFile();
writer.close();
}
//Send a report back and close the connection
out.println("Server received " + numMessages + " messages");
out.println("Done");
server.removeOldClient(this);
out.close();
in.close();
client.close();
}
catch (IOExceptione) {
e.printStackTrace();
}
finally{
try{
System.out.println("!!!!! Closing connection... !!!!!");
client.close();
}
catch(IOExceptione){
System.out.println("Unable to disconnect!");
System.exit(1);
}
}
}
}
// Power function to return value of a ^ b mod N
privatestaticlongpower(longa, longb, longN){
if (b == 1)
returna;
else
return (((long)Math.pow(a, b)) % N);
}
/*
* The following methods are all for the encryption and
* decryption of all messages sent / received.
*/
//Encrypts the string
publicstaticStringencrypt(Stringmessage, intkey) {
Stringencrypted = "";
//Convert key to binary number
StringbinaryKey = Integer.toBinaryString(key);
binaryKey = binaryKey.substring(binaryKey.length() - 8);
//Converts the string to ascii, then to binary
StringnewMessage = convertToAscii(message);
newMessage = convertAsciiToBinary(newMessage);
//Creates array of encrypted words
String[] binaryArray = newMessage.split(" ");
String[] encryptedWords = newString[binaryArray.length];
for(inti = 0; i < binaryArray.length; i++) {
encryptedWords[i] = binaryAdd(binaryArray[i], binaryKey);
}
//Adds encrypted words all into one string
for(intq = 0; q < encryptedWords.length; q++) {
encrypted += encryptedWords[q] + " ";
}
returnencrypted;
}
//Decrypts the encrypted string
publicstaticStringdecrypt(Stringmessage, intkey) {
Stringdecrypted = "";
//Convert key to binary number
StringbinaryKey = Integer.toBinaryString(key);
binaryKey = binaryKey.substring(binaryKey.length() - 8);
//Converts encrypted binary to decrypted binary
String[] decryptedWords = message.split(" ");
for(inti = 0; i < decryptedWords.length; i++) {
decryptedWords[i] = binaryAdd(decryptedWords[i], binaryKey);
}
//Converts binary to ascii
String[] asciiWords = newString[decryptedWords.length];
for(intj = 0; j < decryptedWords.length; j++) {
inttemp = Integer.parseInt(decryptedWords[j],2);
asciiWords[j] = String.valueOf(temp);
}
//Converts array to string to be decrypted
for(intq = 0; q < decryptedWords.length; q++) {
decrypted += asciiWords[q] + " ";
}
//Converts the ascii to binary
decrypted = convertBack(decrypted);
returndecrypted;
}
//Does binary addition for encryption
publicstaticStringbinaryAdd(Stringword, Stringkey){
StringnewString = "";
for (inti = 0; i < 8; i++){
if (word.charAt(i) == key.charAt(i))
newString += "0";
else
newString += "1";
}
returnnewString;
}
//Converts words to ascii characters
publicstaticStringconvertToAscii(Stringmessage) {
byte[] ascii = message.getBytes(StandardCharsets.US_ASCII);
StringasciiString = Arrays.toString(ascii);
asciiString = removeJunk(asciiString);
returnasciiString;
}
//Converts Ascii characters to binary
publicstaticStringconvertAsciiToBinary(Stringascii) {
Stringbinary = "";
String[] arr = ascii.split(" ");
String[] converted = newString[arr.length];
//Converts all ascii values to binary
for(inti = 0; i < converted.length; i++) {
intnum = Integer.valueOf(arr[i]);
converted[i] = Integer.toBinaryString(num);
}
//Adds 0's to front of binary numbers if they're shorter 8
for(intj = 0; j < converted.length; j++) {
while(converted[j].length() < 8) {
converted[j] = "0" + converted[j];
}
}
//Converts string array to string
for(intq = 0; q < converted.length; q++) {
binary += converted[q] + " ";
}
returnbinary;
}
//Makes string pretty
publicstaticStringremoveJunk(Stringmessage) {
//Removes junk from string
StringnewMessage = message.replaceAll(",", "");
newMessage = newMessage.replaceAll("\\[", "");
newMessage = newMessage.replaceAll("\\]", "");
returnnewMessage;
}
//Converts ascii to real characters
publicstaticStringconvertBack(Stringmessage) {
StringconvertedMessage = "";
//Split string on spaces and convert from ascii values to letters
String[] arr = message.split(" ");
for(Stringstr: arr) {
intnum = (Integer.valueOf(str));
chara = (char)num;
convertedMessage += "" + a;
}
returnconvertedMessage;
}
}