content: import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.io.PrintWriter;
  import java.net.ServerSocket;
  import java.net.Socket;
  
  public class EchoServer {
  	ServerSocket serverSocket;	
  	public EchoServer(){		
  	}
  	
  	public void start() {		
  		try {
  			serverSocket = new ServerSocket(12321);
  			while(true){
  				Thread clientThread = new Thread(new ClientHandler(serverSocket.accept()));
  				clientThread.start();
  			}
  		} catch (IOException e) {
  			e.printStackTrace();
  		} finally {
  			try {
  				System.out.println("closing server socket");
  				serverSocket.close();
  			} catch (IOException e) {
  				e.printStackTrace();
  			}
  		}
  		
  	}
  	
  	public static void main(String[] args) {
  		EchoServer es = new EchoServer();
  		es.start();
  	}
  }
  
  class ClientHandler implements Runnable {
  	private static int numConnections;
  	private int connectionId = 0;
  	Socket clientSocket;
  	
  	public ClientHandler(Socket s) {
  		connectionId = numConnections++;
  		System.out.println("handling connection, #" + connectionId);
  		clientSocket = s;
  	}
  
  	public void run() {
  		PrintWriter out = null;
  		BufferedReader in = null;
  		try {
  			out = new PrintWriter(clientSocket.getOutputStream(), true);
  			in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
  			String inputLine, outputLine;
  			while((inputLine = in.readLine()) != null){
  				outputLine = inputLine;
  				System.out.println("received: " + outputLine);
  				out.write(outputLine+"\n");
  				out.flush();
  				if (outputLine.equals("exit"))
  					break;
  			}
  		} catch(Exception e) {
  			e.printStackTrace();
  		} finally {
  			out.close();
  			try {
  				in.close();
  				clientSocket.close();
  				System.out.println("closing connection, #" + connectionId);
  			} catch (IOException e) {
  				e.printStackTrace();
  			}
  		}
  	}
  }
  