import java.net.Socket;
import java.net.ServerSocket;
import java.io.InputStream;
import java.io.OutputStream;

class ServerLoop implements Runnable {
    java.net.ServerSocket server_port;

    public ServerLoop(java.net.ServerSocket s) {
	server_port = s;
    }

    private void print_log(String msg) {
	System.out.println("Thread: " + Thread.currentThread().getName() + ": " + msg);
    }

    private void print_err(String msg) {
	System.err.println("Thread: " + Thread.currentThread().getName() + ": " + msg);
    }

    public void run() {
	byte buffer[] = new byte[1000];
	int n;

	while (true) {
	    java.net.Socket connection;
	    try {
		connection = server_port.accept();
	    } catch (java.io.IOException ex) {
		print_log("error accepting connection: " + ex);
		print_log("terminating.");
		return;
	    }
	    print_log("serving connection from " + connection.getInetAddress());
	    try {
		java.io.InputStream input = connection.getInputStream();
		java.io.OutputStream output = connection.getOutputStream();

		while ((n = input.read(buffer)) > 0)
		    output.write(buffer, 0, n);
		connection.close();
	    } catch (java.io.IOException ex) {
		print_err("error while servinging connection: " + ex);
	    }
	    try {
		connection.close();
		print_err("connection with " + connection.getInetAddress() + " is now closed.");
	    } catch (java.io.IOException ex) {
		print_err("error closing connection: " + ex);
	    }
	}
    }
}

public class ThreadedEchoServer {

    public static void main(String [] args) throws Exception {

	int port_number = 4567;
	int thread_count = 5;

	switch (args.length) {
	case 2: thread_count = Integer.parseInt(args[0]);
	case 1: port_number = Integer.parseInt(args[0]);
	case 0: break;
	default:
	    System.err.println("Usage: ThreadedEchoServer [port (default=4567)] [thread-count (default=5)]");
	    System.exit(1);
	}

	java.net.ServerSocket server_port = new java.net.ServerSocket(port_number);

	Thread threads[] = new Thread[thread_count];

	for (int i = 0; i < thread_count; ++i) {
	    threads[i] = new Thread(new ServerLoop(server_port), "S"+i);
	    threads[i].start();
	}

	for (int i = 0; i < thread_count; ++i)
	    threads[i].join();

	server_port.close();
    }
}
