diff --git a/AcceptThread.java b/AcceptThread.java new file mode 100644 index 0000000..b83f225 --- /dev/null +++ b/AcceptThread.java @@ -0,0 +1,56 @@ +// MIT License + +// Copyright (c) 2017 Matthew Chen, Arc676/Alessandro Vinciguerra + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import java.io.*; +import java.util.*; +import java.net.*; + +public class AcceptThread extends Thread{ + + public boolean running = true; + + private ServerSocket sock; + private Server server; + + public AcceptThread(ServerSocket sock, Server server){ + this.sock = sock; + this.server = server; + } + + public void run(){ + while (running){ + try { + Socket cSock = sock.accept(); + server.addClientHandler(new ClientHandler(cSock, server)); + } catch (SocketException e){ + if (e.getMessage().equals("Socket closed")){ + running = false; + break; + } + } catch (Exception e) { + System.err.println("Oh noes!"); + e.printStackTrace(); + } + } + } + +} \ No newline at end of file diff --git a/Client.java b/Client.java new file mode 100644 index 0000000..5fbf772 --- /dev/null +++ b/Client.java @@ -0,0 +1,117 @@ +// MIT License + +// Copyright (c) 2017 Matthew Chen, Arc676/Alessandro Vinciguerra + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import java.io.*; +import java.net.*; +import java.util.*; + +//port number: 4267 + +public class Client{ + + //terminal IO + private Scanner sc; + + //network IO + private Socket sock; + private PrintWriter out; + private BufferedReader in; + private int port; + private String host; + + private String username; + + private MsgThread msgThread; + + public Client(String[] args) { + sc = new Scanner(System.in); + if (args.length == 3){ + username = args[0]; + host = args[1]; + try { + port = Integer.parseInt(args[2]); + } catch (NumberFormatException e){ + System.err.println("Invalid port input. Using default port 4267."); + port = 4267; + } + } else { + while (true){ + System.out.print("Enter username: "); + username = sc.nextLine(); + if (username.equals("server") || username.equals("global")){ + System.out.println("Error: reserved usernames cannot be used"); + } else { + break; + } + } + System.out.print("Enter host: "); + host = sc.nextLine(); + try { + System.out.print("Enter port number: "); + port = Integer.parseInt(sc.nextLine()); + } catch (NumberFormatException e){ + System.err.println("Invalid port input. Using default port 4267."); + port = 4267; + } + } + try { + sock = new Socket(host, port); + out = new PrintWriter(sock.getOutputStream(), true); + out.println(username); + in = new BufferedReader(new InputStreamReader(sock.getInputStream())); + msgThread = new MsgThread(in, null, username); + msgThread.start(); + } catch (IOException e){ + System.err.println("IOException occurred."); + return; + } + + run(); + } + + private void run(){ + System.out.println("Begin chat with " + host + " on port " + port); + String inLine = ""; + while (true){ + String toSend = sc.nextLine(); + out.println(username + ": " + toSend); + if (toSend.equals("/disconnect") || !msgThread.running){ + System.out.println("Exiting..."); + break; + } else { + System.out.println(username + ": " + toSend); + } + } + try { + msgThread.running = false; + sock.close(); + } catch (IOException e){ + System.err.println("err...."); + } + System.out.println("Chat terminated"); + } + + public static void main(String[] args) { + new Client(args); + } + +} \ No newline at end of file diff --git a/ClientHandler.java b/ClientHandler.java new file mode 100644 index 0000000..ac8d5af --- /dev/null +++ b/ClientHandler.java @@ -0,0 +1,53 @@ +// MIT License + +// Copyright (c) 2017 Matthew Chen, Arc676/Alessandro Vinciguerra + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import java.net.*; +import java.io.*; + +public class ClientHandler{ + public PrintWriter out; + public BufferedReader in; + public MsgThread msgThread; + public String username; + + public ClientHandler(Socket clientSocket, Server server){ + try{ + out = new PrintWriter(clientSocket.getOutputStream(), true); + in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + username = in.readLine(); + server.broadcastToClients(username + " connected", "global"); + msgThread = new MsgThread(in, server, username); + msgThread.start(); + }catch(Exception e){ + System.out.println("Error by the way"); + e.printStackTrace(); + } + } + + public void send(String text){ + out.println(text); + } + + public void stopRunning(){ + msgThread.running = false; + } +} diff --git a/LICENSE b/LICENSE index 8864d4a..3fceada 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 +Copyright (c) 2017 Matthew Chen, Arc676/Alessandro Vinciguerra Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MsgThread.java b/MsgThread.java new file mode 100644 index 0000000..18c0509 --- /dev/null +++ b/MsgThread.java @@ -0,0 +1,70 @@ +// MIT License + +// Copyright (c) 2017 Matthew Chen, Arc676/Alessandro Vinciguerra + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import java.io.*; +import java.util.*; +import java.net.*; + +public class MsgThread extends Thread { + + public boolean running = true; + + private BufferedReader in; + private Server server; + private String username; + + public MsgThread(BufferedReader in, Server server, String username){ + this.in = in; + this.server = server; + this.username = username; + } + + public void run(){ + String inLine = ""; + while (running){ + try { + inLine = in.readLine(); + if (inLine == null || inLine.substring(inLine.indexOf(":") + 2).equals("/disconnect")){ + print(username + " disconnected"); + running = false; + } else { + print(inLine); + } + } catch(SocketException e){ + if(e.getMessage().equals("Socket closed")){ + System.out.println("Socket closed"); + running = false; + } + } catch (IOException e){ + e.printStackTrace(); + } + } + } + + private void print(String text){ + if (server != null){ + server.broadcastToClients(text, username); + } else { + System.out.println(text); + } + } +} \ No newline at end of file diff --git a/README.TXT b/README.TXT new file mode 100644 index 0000000..43978ec --- /dev/null +++ b/README.TXT @@ -0,0 +1,4 @@ +PROJECT TITLE: Chat Program +VERSION or DATE: 1.1 +AUTHORS: Matthew Chen, Arc676/Alessandro Vinciguerra +LICENSE: MIT; See LICENSE for more details \ No newline at end of file diff --git a/Server.java b/Server.java new file mode 100644 index 0000000..d0ad5f3 --- /dev/null +++ b/Server.java @@ -0,0 +1,101 @@ +// MIT License + +// Copyright (c) 2017 Matthew Chen, Arc676/Alessandro Vinciguerra + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import java.util.*; +import java.io.*; +import java.net.*; + +public class Server{ + + private int portNum; + private String yourLine; + private ServerSocket serverSocket; + private ArrayList clientArray; + + public Server(String givenPort){ + clientArray = new ArrayList(); + Scanner scan = new Scanner(System.in); + try { + if (givenPort.equals("")){ + System.out.print("Enter port: "); + portNum = Integer.parseInt(scan.nextLine()); + }else{ + portNum = Integer.parseInt(givenPort); + } + } catch (NumberFormatException e){ + System.err.println("Invalid port. Using default of 4267"); + portNum = 4267; + } + try { + //Listens for socket + System.out.println("Hosting chat server on port " + portNum); + serverSocket = new ServerSocket(portNum); + AcceptThread acceptThread = new AcceptThread(serverSocket, this); + acceptThread.start(); + + while(true){ + yourLine = scan.nextLine(); + System.out.println("Server: " + yourLine); + + broadcastToClients("Server: " + yourLine, "server"); + + if (yourLine.equals("/close")){ + break; + } + } + acceptThread.running = false; + for (int i = 0; i < clientArray.size(); i++){ + clientArray.get(i).stopRunning(); + } + System.out.println("Closing server"); + serverSocket.close(); + }catch(Exception e){ + System.out.println("Error by the way"); + e.printStackTrace(); + } + } + + public void addClientHandler(ClientHandler clientHandler){ + clientArray.add(clientHandler); + } + + public void broadcastToClients(String text, String source){ + for (ClientHandler ch : clientArray){ + if(!ch.username.equals(source)){ + ch.send(text); + } + } + + if (!source.equals("server")){ + System.out.println(text); + } + } + + public static void main(String[] args){ + if (args.length == 1){ + new Server(args[0]); + }else{ + new Server(""); + } + } + +} \ No newline at end of file