├── README.md └── src └── com └── thecherno └── chernochat ├── Client.java ├── ClientWindow.java ├── Login.java ├── OnlineUsers.java └── server ├── Server.java ├── ServerClient.java ├── ServerMain.java └── UniqueIdentifier.java /README.md: -------------------------------------------------------------------------------- 1 | ChernoChat 2 | ========== 3 | 4 | All of the code for the Cherno Chat project, as well as the code for the individual episodes. 5 | -------------------------------------------------------------------------------- /src/com/thecherno/chernochat/Client.java: -------------------------------------------------------------------------------- 1 | package com.thecherno.chernochat; 2 | 3 | import java.io.IOException; 4 | import java.net.DatagramPacket; 5 | import java.net.DatagramSocket; 6 | import java.net.InetAddress; 7 | import java.net.SocketException; 8 | import java.net.UnknownHostException; 9 | 10 | public class Client { 11 | private static final long serialVersionUID = 1L; 12 | 13 | private DatagramSocket socket; 14 | 15 | private String name, address; 16 | private int port; 17 | private InetAddress ip; 18 | private Thread send; 19 | private int ID = -1; 20 | 21 | public Client(String name, String address, int port) { 22 | this.name = name; 23 | this.address = address; 24 | this.port = port; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public String getAddress() { 32 | return address; 33 | } 34 | 35 | public int getPort() { 36 | return port; 37 | } 38 | 39 | public boolean openConnection(String address) { 40 | try { 41 | socket = new DatagramSocket(); 42 | ip = InetAddress.getByName(address); 43 | } catch (UnknownHostException e) { 44 | e.printStackTrace(); 45 | return false; 46 | } catch (SocketException e) { 47 | e.printStackTrace(); 48 | return false; 49 | } 50 | return true; 51 | } 52 | 53 | public String receive() { 54 | byte[] data = new byte[1024]; 55 | DatagramPacket packet = new DatagramPacket(data, data.length); 56 | try { 57 | socket.receive(packet); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } 61 | String message = new String(packet.getData()); 62 | return message; 63 | } 64 | 65 | public void send(final byte[] data) { 66 | send = new Thread("Send") { 67 | public void run() { 68 | DatagramPacket packet = new DatagramPacket(data, data.length, ip, port); 69 | try { 70 | socket.send(packet); 71 | } catch (IOException e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | }; 76 | send.start(); 77 | } 78 | 79 | public void close() { 80 | new Thread() { 81 | public void run() { 82 | synchronized (socket) { 83 | socket.close(); 84 | } 85 | } 86 | }.start(); 87 | } 88 | 89 | public void setID(int ID) { 90 | this.ID = ID; 91 | } 92 | 93 | public int getID() { 94 | return ID; 95 | } 96 | 97 | } -------------------------------------------------------------------------------- /src/com/thecherno/chernochat/ClientWindow.java: -------------------------------------------------------------------------------- 1 | package com.thecherno.chernochat; 2 | 3 | import java.awt.GridBagConstraints; 4 | import java.awt.GridBagLayout; 5 | import java.awt.Insets; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.awt.event.KeyAdapter; 9 | import java.awt.event.KeyEvent; 10 | import java.awt.event.WindowAdapter; 11 | import java.awt.event.WindowEvent; 12 | import java.util.Arrays; 13 | 14 | import javax.swing.JButton; 15 | import javax.swing.JFrame; 16 | import javax.swing.JPanel; 17 | import javax.swing.JScrollPane; 18 | import javax.swing.JTextArea; 19 | import javax.swing.JTextField; 20 | import javax.swing.UIManager; 21 | import javax.swing.border.EmptyBorder; 22 | import javax.swing.text.DefaultCaret; 23 | import javax.swing.JMenuBar; 24 | import javax.swing.JMenu; 25 | import javax.swing.JMenuItem; 26 | 27 | public class ClientWindow extends JFrame implements Runnable { 28 | private static final long serialVersionUID = 1L; 29 | 30 | private JPanel contentPane; 31 | private JTextField txtMessage; 32 | private JTextArea history; 33 | private DefaultCaret caret; 34 | private Thread run, listen; 35 | private Client client; 36 | 37 | private boolean running = false; 38 | private JMenuBar menuBar; 39 | private JMenu mnFile; 40 | private JMenuItem mntmOnlineUsers; 41 | private JMenuItem mntmExit; 42 | 43 | private OnlineUsers users; 44 | 45 | public ClientWindow(String name, String address, int port) { 46 | setTitle("Cherno Chat Client"); 47 | client = new Client(name, address, port); 48 | boolean connect = client.openConnection(address); 49 | if (!connect) { 50 | System.err.println("Connection failed!"); 51 | console("Connection failed!"); 52 | } 53 | createWindow(); 54 | console("Attempting a connection to " + address + ":" + port + ", user: " + name); 55 | String connection = "/c/" + name + "/e/"; 56 | client.send(connection.getBytes()); 57 | users = new OnlineUsers(); 58 | running = true; 59 | run = new Thread(this, "Running"); 60 | run.start(); 61 | } 62 | 63 | private void createWindow() { 64 | try { 65 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 66 | } catch (Exception e1) { 67 | e1.printStackTrace(); 68 | } 69 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 70 | setSize(880, 550); 71 | setLocationRelativeTo(null); 72 | 73 | menuBar = new JMenuBar(); 74 | setJMenuBar(menuBar); 75 | 76 | mnFile = new JMenu("File"); 77 | menuBar.add(mnFile); 78 | 79 | mntmOnlineUsers = new JMenuItem("Online Users"); 80 | mntmOnlineUsers.addActionListener(new ActionListener() { 81 | public void actionPerformed(ActionEvent e) { 82 | users.setVisible(true); 83 | } 84 | }); 85 | mnFile.add(mntmOnlineUsers); 86 | 87 | mntmExit = new JMenuItem("Exit"); 88 | mnFile.add(mntmExit); 89 | contentPane = new JPanel(); 90 | contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); 91 | setContentPane(contentPane); 92 | 93 | GridBagLayout gbl_contentPane = new GridBagLayout(); 94 | gbl_contentPane.columnWidths = new int[] { 28, 815, 30, 7 }; // SUM = 880 95 | gbl_contentPane.rowHeights = new int[] { 25, 485, 40 }; // SUM = 550 96 | contentPane.setLayout(gbl_contentPane); 97 | 98 | history = new JTextArea(); 99 | history.setEditable(false); 100 | JScrollPane scroll = new JScrollPane(history); 101 | caret = (DefaultCaret) history.getCaret(); 102 | caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); 103 | GridBagConstraints scrollConstraints = new GridBagConstraints(); 104 | scrollConstraints.insets = new Insets(0, 0, 5, 5); 105 | scrollConstraints.fill = GridBagConstraints.BOTH; 106 | scrollConstraints.gridx = 0; 107 | scrollConstraints.gridy = 0; 108 | scrollConstraints.gridwidth = 3; 109 | scrollConstraints.gridheight = 2; 110 | scrollConstraints.weightx = 1; 111 | scrollConstraints.weighty = 1; 112 | scrollConstraints.insets = new Insets(0, 5, 0, 0); 113 | contentPane.add(scroll, scrollConstraints); 114 | 115 | txtMessage = new JTextField(); 116 | txtMessage.addKeyListener(new KeyAdapter() { 117 | public void keyPressed(KeyEvent e) { 118 | if (e.getKeyCode() == KeyEvent.VK_ENTER) { 119 | send(txtMessage.getText(), true); 120 | } 121 | } 122 | }); 123 | GridBagConstraints gbc_txtMessage = new GridBagConstraints(); 124 | gbc_txtMessage.insets = new Insets(0, 0, 0, 5); 125 | gbc_txtMessage.fill = GridBagConstraints.HORIZONTAL; 126 | gbc_txtMessage.gridx = 0; 127 | gbc_txtMessage.gridy = 2; 128 | gbc_txtMessage.gridwidth = 2; 129 | gbc_txtMessage.weightx = 1; 130 | gbc_txtMessage.weighty = 0; 131 | contentPane.add(txtMessage, gbc_txtMessage); 132 | txtMessage.setColumns(10); 133 | 134 | JButton btnSend = new JButton("Send"); 135 | btnSend.addActionListener(new ActionListener() { 136 | public void actionPerformed(ActionEvent e) { 137 | send(txtMessage.getText(), true); 138 | } 139 | }); 140 | GridBagConstraints gbc_btnSend = new GridBagConstraints(); 141 | gbc_btnSend.insets = new Insets(0, 0, 0, 5); 142 | gbc_btnSend.gridx = 2; 143 | gbc_btnSend.gridy = 2; 144 | gbc_btnSend.weightx = 0; 145 | gbc_btnSend.weighty = 0; 146 | contentPane.add(btnSend, gbc_btnSend); 147 | 148 | addWindowListener(new WindowAdapter() { 149 | public void windowClosing(WindowEvent e) { 150 | String disconnect = "/d/" + client.getID() + "/e/"; 151 | send(disconnect, false); 152 | running = false; 153 | client.close(); 154 | } 155 | }); 156 | 157 | setVisible(true); 158 | 159 | txtMessage.requestFocusInWindow(); 160 | } 161 | 162 | public void run() { 163 | listen(); 164 | } 165 | 166 | private void send(String message, boolean text) { 167 | if (message.equals("")) return; 168 | if (text) { 169 | message = client.getName() + ": " + message; 170 | message = "/m/" + message + "/e/"; 171 | txtMessage.setText(""); 172 | } 173 | client.send(message.getBytes()); 174 | } 175 | 176 | public void listen() { 177 | listen = new Thread("Listen") { 178 | public void run() { 179 | while (running) { 180 | String message = client.receive(); 181 | if (message.startsWith("/c/")) { 182 | client.setID(Integer.parseInt(message.split("/c/|/e/")[1])); 183 | console("Successfully connected to server! ID: " + client.getID()); 184 | } else if (message.startsWith("/m/")) { 185 | String text = message.substring(3); 186 | text = text.split("/e/")[0]; 187 | console(text); 188 | } else if (message.startsWith("/i/")) { 189 | String text = "/i/" + client.getID() + "/e/"; 190 | send(text, false); 191 | } else if (message.startsWith("/u/")) { 192 | String[] u = message.split("/u/|/n/|/e/"); 193 | users.update(Arrays.copyOfRange(u, 1, u.length - 1)); 194 | } 195 | } 196 | } 197 | }; 198 | listen.start(); 199 | } 200 | 201 | public void console(String message) { 202 | history.append(message + "\n\r"); 203 | history.setCaretPosition(history.getDocument().getLength()); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/com/thecherno/chernochat/Login.java: -------------------------------------------------------------------------------- 1 | package com.thecherno.chernochat; 2 | 3 | import java.awt.EventQueue; 4 | import java.awt.event.ActionEvent; 5 | import java.awt.event.ActionListener; 6 | 7 | import javax.swing.JButton; 8 | import javax.swing.JFrame; 9 | import javax.swing.JLabel; 10 | import javax.swing.JPanel; 11 | import javax.swing.JTextField; 12 | import javax.swing.UIManager; 13 | import javax.swing.UnsupportedLookAndFeelException; 14 | import javax.swing.border.EmptyBorder; 15 | 16 | public class Login extends JFrame { 17 | private static final long serialVersionUID = 1L; 18 | 19 | private JPanel contentPane; 20 | private JTextField txtName; 21 | private JTextField txtAddress; 22 | private JTextField txtPort; 23 | private JLabel lblIpAddress; 24 | private JLabel lblPort; 25 | private JLabel lblAddressDesc; 26 | private JLabel lblPortDesc; 27 | 28 | public Login() { 29 | try { 30 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 31 | } catch (Exception e1) { 32 | e1.printStackTrace(); 33 | } 34 | setResizable(false); 35 | setTitle("Login"); 36 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 37 | setSize(300, 380); 38 | setLocationRelativeTo(null); 39 | contentPane = new JPanel(); 40 | contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); 41 | setContentPane(contentPane); 42 | contentPane.setLayout(null); 43 | 44 | txtName = new JTextField(); 45 | txtName.setBounds(67, 50, 165, 28); 46 | contentPane.add(txtName); 47 | txtName.setColumns(10); 48 | 49 | JLabel lblName = new JLabel("Name:"); 50 | lblName.setBounds(127, 34, 45, 16); 51 | contentPane.add(lblName); 52 | 53 | txtAddress = new JTextField(); 54 | txtAddress.setBounds(67, 116, 165, 28); 55 | contentPane.add(txtAddress); 56 | txtAddress.setColumns(10); 57 | 58 | lblIpAddress = new JLabel("IP Address:"); 59 | lblIpAddress.setBounds(111, 96, 77, 16); 60 | contentPane.add(lblIpAddress); 61 | 62 | txtPort = new JTextField(); 63 | txtPort.setColumns(10); 64 | txtPort.setBounds(67, 191, 165, 28); 65 | contentPane.add(txtPort); 66 | 67 | lblPort = new JLabel("Port:"); 68 | lblPort.setBounds(133, 171, 34, 16); 69 | contentPane.add(lblPort); 70 | 71 | lblAddressDesc = new JLabel("(eg. 192.168.0.2)"); 72 | lblAddressDesc.setBounds(94, 142, 112, 16); 73 | contentPane.add(lblAddressDesc); 74 | 75 | lblPortDesc = new JLabel("(eg. 8192)"); 76 | lblPortDesc.setBounds(116, 218, 68, 16); 77 | contentPane.add(lblPortDesc); 78 | 79 | JButton btnLogin = new JButton("Login"); 80 | btnLogin.addActionListener(new ActionListener() { 81 | public void actionPerformed(ActionEvent e) { 82 | String name = txtName.getText(); 83 | String address = txtAddress.getText(); 84 | int port = Integer.parseInt(txtPort.getText()); 85 | login(name, address, port); 86 | } 87 | }); 88 | btnLogin.setBounds(91, 311, 117, 29); 89 | contentPane.add(btnLogin); 90 | } 91 | 92 | private void login(String name, String address, int port) { 93 | dispose(); 94 | new ClientWindow(name, address, port); 95 | } 96 | 97 | public static void main(String[] args) { 98 | EventQueue.invokeLater(new Runnable() { 99 | public void run() { 100 | try { 101 | Login frame = new Login(); 102 | frame.setVisible(true); 103 | } catch (Exception e) { 104 | e.printStackTrace(); 105 | } 106 | } 107 | }); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/com/thecherno/chernochat/OnlineUsers.java: -------------------------------------------------------------------------------- 1 | package com.thecherno.chernochat; 2 | 3 | import java.awt.Font; 4 | import java.awt.GridBagConstraints; 5 | import java.awt.GridBagLayout; 6 | 7 | import javax.swing.JFrame; 8 | import javax.swing.JList; 9 | import javax.swing.JPanel; 10 | import javax.swing.JScrollPane; 11 | import javax.swing.border.EmptyBorder; 12 | 13 | public class OnlineUsers extends JFrame { 14 | private static final long serialVersionUID = 1L; 15 | 16 | private JPanel contentPane; 17 | private JList list; 18 | 19 | public OnlineUsers() { 20 | setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 21 | setSize(200, 320); 22 | setTitle("Online Users"); 23 | setLocationRelativeTo(null); 24 | contentPane = new JPanel(); 25 | contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); 26 | setContentPane(contentPane); 27 | GridBagLayout gbl_contentPane = new GridBagLayout(); 28 | gbl_contentPane.columnWidths = new int[] { 0, 0 }; 29 | gbl_contentPane.rowHeights = new int[] { 0, 0 }; 30 | gbl_contentPane.columnWeights = new double[] { 1.0, Double.MIN_VALUE }; 31 | gbl_contentPane.rowWeights = new double[] { 1.0, Double.MIN_VALUE }; 32 | contentPane.setLayout(gbl_contentPane); 33 | 34 | list = new JList(); 35 | GridBagConstraints gbc_list = new GridBagConstraints(); 36 | gbc_list.fill = GridBagConstraints.BOTH; 37 | gbc_list.gridx = 0; 38 | gbc_list.gridy = 0; 39 | JScrollPane p = new JScrollPane(); 40 | p.setViewportView(list); 41 | contentPane.add(p, gbc_list); 42 | list.setFont(new Font("Verdana", 0, 24)); 43 | } 44 | 45 | public void update(String[] users) { 46 | list.setListData(users); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/com/thecherno/chernochat/server/Server.java: -------------------------------------------------------------------------------- 1 | package com.thecherno.chernochat.server; 2 | 3 | import java.io.IOException; 4 | import java.net.DatagramPacket; 5 | import java.net.DatagramSocket; 6 | import java.net.InetAddress; 7 | import java.net.SocketException; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Scanner; 11 | 12 | public class Server implements Runnable { 13 | 14 | private List clients = new ArrayList(); 15 | private List clientResponse = new ArrayList(); 16 | 17 | private DatagramSocket socket; 18 | private int port; 19 | private boolean running = false; 20 | private Thread run, manage, send, receive; 21 | private final int MAX_ATTEMPTS = 5; 22 | 23 | private boolean raw = false; 24 | 25 | public Server(int port) { 26 | this.port = port; 27 | try { 28 | socket = new DatagramSocket(port); 29 | } catch (SocketException e) { 30 | e.printStackTrace(); 31 | return; 32 | } 33 | run = new Thread(this, "Server"); 34 | run.start(); 35 | } 36 | 37 | public void run() { 38 | running = true; 39 | System.out.println("Server started on port " + port); 40 | manageClients(); 41 | receive(); 42 | Scanner scanner = new Scanner(System.in); 43 | while (running) { 44 | String text = scanner.nextLine(); 45 | if (!text.startsWith("/")) { 46 | sendToAll("/m/Server: " + text + "/e/"); 47 | continue; 48 | } 49 | text = text.substring(1); 50 | if (text.equals("raw")) { 51 | if (raw) System.out.println("Raw mode off."); 52 | else System.out.println("Raw mode on."); 53 | raw = !raw; 54 | } else if (text.equals("clients")) { 55 | System.out.println("Clients:"); 56 | System.out.println("========"); 57 | for (int i = 0; i < clients.size(); i++) { 58 | ServerClient c = clients.get(i); 59 | System.out.println(c.name + "(" + c.getID() + "): " + c.address.toString() + ":" + c.port); 60 | } 61 | System.out.println("========"); 62 | } else if (text.startsWith("kick")) { 63 | String name = text.split(" ")[1]; 64 | int id = -1; 65 | boolean number = true; 66 | try { 67 | id = Integer.parseInt(name); 68 | } catch (NumberFormatException e) { 69 | number = false; 70 | } 71 | if (number) { 72 | boolean exists = false; 73 | for (int i = 0; i < clients.size(); i++) { 74 | if (clients.get(i).getID() == id) { 75 | exists = true; 76 | break; 77 | } 78 | } 79 | if (exists) disconnect(id, true); 80 | else System.out.println("Client " + id + " doesn't exist! Check ID number."); 81 | } else { 82 | for (int i = 0; i < clients.size(); i++) { 83 | ServerClient c = clients.get(i); 84 | if (name.equals(c.name)) { 85 | disconnect(c.getID(), true); 86 | break; 87 | } 88 | } 89 | } 90 | } else if (text.equals("help")) { 91 | printHelp(); 92 | } else if (text.equals("quit")) { 93 | quit(); 94 | } else { 95 | System.out.println("Unknown command."); 96 | printHelp(); 97 | } 98 | } 99 | scanner.close(); 100 | } 101 | 102 | private void printHelp() { 103 | System.out.println("Here is a list of all available commands:"); 104 | System.out.println("========================================="); 105 | System.out.println("/raw - enables raw mode."); 106 | System.out.println("/clients - shows all connected clients."); 107 | System.out.println("/kick [users ID or username] - kicks a user."); 108 | System.out.println("/help - shows this help message."); 109 | System.out.println("/quit - shuts down the server."); 110 | } 111 | 112 | private void manageClients() { 113 | manage = new Thread("Manage") { 114 | public void run() { 115 | while (running) { 116 | sendToAll("/i/server"); 117 | sendStatus(); 118 | try { 119 | Thread.sleep(2000); 120 | } catch (InterruptedException e) { 121 | e.printStackTrace(); 122 | } 123 | for (int i = 0; i < clients.size(); i++) { 124 | ServerClient c = clients.get(i); 125 | if (!clientResponse.contains(c.getID())) { 126 | if (c.attempt >= MAX_ATTEMPTS) { 127 | disconnect(c.getID(), false); 128 | } else { 129 | c.attempt++; 130 | } 131 | } else { 132 | clientResponse.remove(new Integer(c.getID())); 133 | c.attempt = 0; 134 | } 135 | } 136 | } 137 | } 138 | }; 139 | manage.start(); 140 | } 141 | 142 | private void sendStatus() { 143 | if (clients.size() <= 0) return; 144 | String users = "/u/"; 145 | for (int i = 0; i < clients.size() - 1; i++) { 146 | users += clients.get(i).name + "/n/"; 147 | } 148 | users += clients.get(clients.size() - 1).name + "/e/"; 149 | sendToAll(users); 150 | } 151 | 152 | private void receive() { 153 | receive = new Thread("Receive") { 154 | public void run() { 155 | while (running) { 156 | byte[] data = new byte[1024]; 157 | DatagramPacket packet = new DatagramPacket(data, data.length); 158 | try { 159 | socket.receive(packet); 160 | } catch (SocketException e) { 161 | } catch (IOException e) { 162 | e.printStackTrace(); 163 | } 164 | process(packet); 165 | } 166 | } 167 | }; 168 | receive.start(); 169 | } 170 | 171 | private void sendToAll(String message) { 172 | if (message.startsWith("/m/")) { 173 | String text = message.substring(3); 174 | text = text.split("/e/")[0]; 175 | System.out.println(message); 176 | } 177 | for (int i = 0; i < clients.size(); i++) { 178 | ServerClient client = clients.get(i); 179 | send(message.getBytes(), client.address, client.port); 180 | } 181 | } 182 | 183 | private void send(final byte[] data, final InetAddress address, final int port) { 184 | send = new Thread("Send") { 185 | public void run() { 186 | DatagramPacket packet = new DatagramPacket(data, data.length, address, port); 187 | try { 188 | socket.send(packet); 189 | } catch (IOException e) { 190 | e.printStackTrace(); 191 | } 192 | } 193 | }; 194 | send.start(); 195 | } 196 | 197 | private void send(String message, InetAddress address, int port) { 198 | message += "/e/"; 199 | send(message.getBytes(), address, port); 200 | } 201 | 202 | private void process(DatagramPacket packet) { 203 | String string = new String(packet.getData()); 204 | if (raw) System.out.println(string); 205 | if (string.startsWith("/c/")) { 206 | // UUID id = UUID.randomUUID(); 207 | int id = UniqueIdentifier.getIdentifier(); 208 | String name = string.split("/c/|/e/")[1]; 209 | System.out.println(name + "(" + id + ") connected!"); 210 | clients.add(new ServerClient(name, packet.getAddress(), packet.getPort(), id)); 211 | String ID = "/c/" + id; 212 | send(ID, packet.getAddress(), packet.getPort()); 213 | } else if (string.startsWith("/m/")) { 214 | sendToAll(string); 215 | } else if (string.startsWith("/d/")) { 216 | String id = string.split("/d/|/e/")[1]; 217 | disconnect(Integer.parseInt(id), true); 218 | } else if (string.startsWith("/i/")) { 219 | clientResponse.add(Integer.parseInt(string.split("/i/|/e/")[1])); 220 | } else { 221 | System.out.println(string); 222 | } 223 | } 224 | 225 | private void quit() { 226 | for (int i = 0; i < clients.size(); i++) { 227 | disconnect(clients.get(i).getID(), true); 228 | } 229 | running = false; 230 | socket.close(); 231 | } 232 | 233 | private void disconnect(int id, boolean status) { 234 | ServerClient c = null; 235 | boolean existed = false; 236 | for (int i = 0; i < clients.size(); i++) { 237 | if (clients.get(i).getID() == id) { 238 | c = clients.get(i); 239 | clients.remove(i); 240 | existed = true; 241 | break; 242 | } 243 | } 244 | if (!existed) return; 245 | String message = ""; 246 | if (status) { 247 | message = "Client " + c.name + " (" + c.getID() + ") @ " + c.address.toString() + ":" + c.port + " disconnected."; 248 | } else { 249 | message = "Client " + c.name + " (" + c.getID() + ") @ " + c.address.toString() + ":" + c.port + " timed out."; 250 | } 251 | System.out.println(message); 252 | } 253 | 254 | } 255 | -------------------------------------------------------------------------------- /src/com/thecherno/chernochat/server/ServerClient.java: -------------------------------------------------------------------------------- 1 | package com.thecherno.chernochat.server; 2 | 3 | import java.net.InetAddress; 4 | 5 | public class ServerClient { 6 | 7 | public String name; 8 | public InetAddress address; 9 | public int port; 10 | private final int ID; 11 | public int attempt = 0; 12 | 13 | public ServerClient(String name, InetAddress address, int port, final int ID) { 14 | this.name = name; 15 | this.address = address; 16 | this.port = port; 17 | this.ID = ID; 18 | } 19 | 20 | public int getID() { 21 | return ID; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/com/thecherno/chernochat/server/ServerMain.java: -------------------------------------------------------------------------------- 1 | package com.thecherno.chernochat.server; 2 | 3 | public class ServerMain { 4 | 5 | private int port; 6 | private Server server; 7 | 8 | public ServerMain(int port) { 9 | this.port = port; 10 | server = new Server(port); 11 | } 12 | 13 | public static void main(String[] args) { 14 | int port; 15 | if (args.length != 1) { 16 | System.out.println("Usage: java -jar ChernoChatServer.jar [port]"); 17 | return; 18 | } 19 | port = Integer.parseInt(args[0]); 20 | new ServerMain(port); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/com/thecherno/chernochat/server/UniqueIdentifier.java: -------------------------------------------------------------------------------- 1 | package com.thecherno.chernochat.server; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | public class UniqueIdentifier { 8 | 9 | private static List ids = new ArrayList(); 10 | private static final int RANGE = 10000; 11 | 12 | private static int index = 0; 13 | 14 | static { 15 | for (int i = 0; i < RANGE; i++) { 16 | ids.add(i); 17 | } 18 | Collections.shuffle(ids); 19 | } 20 | 21 | private UniqueIdentifier() { 22 | } 23 | 24 | public static int getIdentifier() { 25 | if (index > ids.size() - 1) index = 0; 26 | return ids.get(index++); 27 | } 28 | 29 | } 30 | --------------------------------------------------------------------------------