// package ch.epfl.compnet; import java.util.*; import java.io.*; import java.net.*; public class MultiThreadServer { public static void main(String args[]) { ServerSocket welcomeSocket = null; Socket connectionSocket = null; try { // Create a socket that listens to port 6789 welcomeSocket = new ServerSocket(6789); int numClients = 0; while(true) { try { // Get a new connection System.out.println("Main thread: waiting for a new client..."); connectionSocket = welcomeSocket.accept(); numClients++; // Start a new thread for the accepted connection System.out.println(numClients + " clients connected"); Thread thread = new Thread(new RequestHandler(connectionSocket, numClients)); thread.start(); } catch (IOException ioex) {} } } catch (IOException ioex) { System.out.println("Failed to open welcomeSocket : " + ioex.getMessage()); } finally { try { if (welcomeSocket != null) welcomeSocket.close(); } catch(IOException e) {} } } } class RequestHandler implements Runnable { Socket socket; int clientNo = 0; public RequestHandler(Socket socket) { this.socket = socket; } public RequestHandler(Socket socket, int clientNo) { this.socket = socket; this.clientNo = clientNo; } private static Map getOccurrences(String message) { Map occurrences = new TreeMap(); String delimiterRegexp = "[^a-zA-Z]+"; Scanner fileScan = new Scanner(message).useDelimiter(delimiterRegexp); while(fileScan.hasNext()){ String word = fileScan.next(); word = word.toLowerCase(); Integer oldCount = occurrences.get(word); if ( oldCount == null ) { oldCount = 0; } occurrences.put(word, oldCount + 1); } return occurrences; } private static void sendResponse(DataOutputStream outToClient, String message) throws IOException { Map occurrences = getOccurrences(message); int numValues = occurrences.size(); outToClient.writeInt(numValues); for (String key: occurrences.keySet()) { String word = key.toString(); int times = occurrences.get(key); // Send the length of the word first int length = word.length(); outToClient.writeInt(length); // Then, send the actual word byte[] b = word.getBytes(); outToClient.write(b, 0, length); // Finally, send the number of times the word appears outToClient.writeInt(times); } } public void run() { Socket connectionSocket = this.socket; DataInputStream inFromClient = null; DataOutputStream outToClient = null; try { // Set reads to timeout after 50 seconds (50000 milliseconds) connectionSocket.setSoTimeout(50000); // Open the input-output streams inFromClient = new DataInputStream(connectionSocket.getInputStream()); outToClient = new DataOutputStream(connectionSocket.getOutputStream()); // This variable controls when the loop should terminate boolean repeatFlag = true; do { System.out.println("Thread " + this.clientNo + ": Waiting to receive a file or close after 50 seconds..."); // Read the lenght of the file int length = inFromClient.readInt(); System.out.println(length); if (length == 0) { // Terminate the connection repeatFlag = false; } else { // Read the file contents into message byte[] bytearray = new byte[length]; inFromClient.readFully(bytearray); String message = new String(bytearray); System.out.println(message); // Call the response handler sendResponse(outToClient, message); } } while (repeatFlag == true); } catch (IOException ioex) { System.out.println("Failed to handle connection : " + ioex.getMessage()); } finally { // Close all input/output/sockets // The stream-closing operations need to be nested in try-catch blocks // Solution inspired by: // http://javarevisited.blogspot.ch/2014/10/right-way-to-close-inputstream-file-resource-in-java.html try { if (outToClient != null) outToClient.close(); } catch(IOException e) {} try { if (inFromClient != null) inFromClient.close(); } catch(IOException e) {} try { if (connectionSocket != null) connectionSocket.close(); } catch(IOException e) {} } } }