// package ch.epfl.compnet; import java.util.*; import java.io.*; import java.net.*; public class TCPServer { 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); } fileScan.close(); return occurrences; } private static void sendResponse(DataOutputStream outToClient, String message) throws IOException { // Perform word-occurrence stats 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); } } private static void handleConnection(Socket connectionSocket) { 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("Waiting to receive a file or close after 50 seconds..."); // Read the length of the file int length = inFromClient.readInt(); System.out.println("The file has length: " + length + " bytes"); 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) {} } } 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); while(true) { try { // Get a new connection System.out.println("Waiting for a new client..."); connectionSocket = welcomeSocket.accept(); // pass the connection socket to the handler System.out.println("Handling new client..."); handleConnection(connectionSocket); } 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) {} } } }