/* Wim H. Hesselink, 6 September 2008
 * Following Graba, Introduction to Network Programming with Java, p. 22 */

import java.util.* ;
import java.io.* ;
import java.net.* ;

class UDPClient implements Runnable {
    protected InetAddress host ;
    protected final int PORT ;
    protected DatagramSocket socket = null ;

    UDPClient(int port) {
	PORT = port ;
	try {
	    host = InetAddress.getLocalHost() ;
	    socket = new DatagramSocket() ; // uses default port
	} catch (UnknownHostException e) {
	    System.out.println("Host not found.") ;
	    System.exit(1) ;
	} catch (IOException e) {
	    e.printStackTrace() ;
	}
    }

    public void run() {
	Scanner scan = new Scanner(System.in) ; // for user input
	System.out.print("> ") ;
	String message = scan.nextLine() ;
	try {
	    while (! message.equals("*quit*")) {
		UDPpacket packet = new UDPpacket(message, host, PORT) ;
		packet.send(socket) ;
		packet = new UDPpacket(socket) ; // response
		System.out.println("Server: " + packet.message) ;
		System.out.print("> ") ;
		message = scan.nextLine() ;
	    }
	} catch (IOException e) {
	    e.printStackTrace() ;
	} finally {
	    System.out.println("Closing connection.\n") ;
	    if (socket != null) socket.close() ;
	}
    }

    public static void main (String[] args) {
	(new UDPClient(args.length == 0 ? 1234 : 
		       Integer.parseInt(args[0]) )).run() ;
    }
}

/* Wim H. Hesselink, 6 September 2008
 * Following Graba, Introduction to Network Programming with Java, p. 22 */

// import java.io.* ;
// import java.net.* ;
class UDPpacket {

    UDPpacket(String message, InetAddress address, int port) {
	this.message = message ;
	this.port = port ;
	this.address = address ;
    }
    
    /** 
     * Reception over socket
     */
    UDPpacket(DatagramSocket ds)
	throws IOException {
	DatagramPacket dp = new DatagramPacket(new byte[256], 256);
	ds.receive(dp) ;
	address = dp.getAddress() ;
	port = dp.getPort() ;
	message = new String(dp.getData(), 0, dp.getLength()) ; 
    }
    
    void send(DatagramSocket ds) 
	throws IOException {
	ds.send(new DatagramPacket(message.getBytes() ,
				   message.length() ,
				   address ,
				   port ) ) ;
    }

    InetAddress address ;
    int port ;
    String message ;
}

/* Wim H. Hesselink, 6 September 2008
 * Following Graba, Introduction to Network Programming with Java, p. 22 */

// import java.io.* ;
// import java.net.* ;

class UDPServer implements Runnable {
    protected final int PORT ; // arbitrary between 1024 and 65535
    protected DatagramSocket socket ;

    UDPServer(int port) {
	PORT = port ;
	System.out.println("Opening port " + port + ".") ;
	try {
	    socket = new DatagramSocket(PORT) ;
	} catch (SocketException e) {
	    System.out.println("Unable to attach to port.") ;
	    System.exit(1) ;
	}
    }

    public void run() { // echoing
	try {
	    while (true) {
		UDPpacket packet = new UDPpacket(socket) ;
		System.out.println("Received: " + packet.message) ;
		packet.message = "Echo: " + packet.message ;
		packet.send(socket) ;
	    }
	} catch (IOException e) {
	    e.printStackTrace() ;
	} finally {
	    System.out.println("\n Closing connection.") ;
	}
    }

    public static void main (String[] args) {
	(new UDPServer(args.length == 0 ? 1234 : 
		       Integer.parseInt(args[0]) )).run() ;
    }
}


