Java - Bidirectional Data transfer using TCP

ServerThread.java

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

	public class ServerThread implements Runnable {
	    ServerSocket serverSocket = null;
	    Socket socket = null;
	    BufferedReader readFromClient = null;
	    BufferedReader readFromServer = null;
	    PrintWriter writeToClient = null;
	    String message = null;

	    public ServerThread() {
	        try {
	            serverSocket = new ServerSocket(4444);
	            System.out.println("Waiting for connection...");
	            socket = serverSocket.accept();
	            System.out.println("Connection accepted...");

	            readFromClient = new BufferedReader(
	                new InputStreamReader(
	                    socket.getInputStream()));
	            writeToClient = new PrintWriter(
	                socket.getOutputStream(), true);
	            readFromServer = new BufferedReader(
	                new InputStreamReader(
	                    System.in));

	            new Thread(this).start();

	            while (true) {
	                message = readFromServer.readLine();
	                writeToClient.println(message);
	                writeToClient.flush();
	                if (message.equalsIgnoreCase("exit")) {
	                    System.exit(0);
	                }
	            }

	        } catch (IOException exp) {
	            exp.printStackTrace();
	        }
	    }

	    public void run() {
	        try {
	            while (true) {
	                String msg = readFromClient.readLine();
	                if (!msg.equalsIgnoreCase("exit")) {
	                    System.out.println(msg);
	                } else {
	                    System.exit(0);
	                }
	            }
	        } catch (Exception exp) {
	            exp.printStackTrace();
	        }
	    }
	}

Server.java

	public class Server {
	    public static void main(String[] args) {
	        new ServerThread();
	    }
	}

ClientThread.java

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

	public class ClientThread implements Runnable {
	    Socket socket = null;
	    BufferedReader readFromClient = null;
	    BufferedReader readFromServer = null;
	    PrintWriter writeToServer = null;
	    String message = null;

	    public ClientThread(Socket socket) {
	        try {
	            this.socket = socket;
	            readFromServer = new BufferedReader(
	                new InputStreamReader(
	                    socket.getInputStream()));
	            writeToServer = new PrintWriter(
	                socket.getOutputStream(), true);
	            readFromClient = new BufferedReader(
	                new InputStreamReader(System.in));

	            new Thread(this).start();

	            while (true) {
	                message = readFromClient.readLine();
	                writeToServer.println(message);
	                writeToServer.flush();
	                if (message.equalsIgnoreCase("exit")) {
	                    System.exit(0);
	                }
	            }
	        } catch (IOException exp) {
	            exp.printStackTrace();
	        }
	    }


	    public void run() {
	        try {
	            while (true) {
	                String msg = readFromServer.readLine();
	                if (!msg.equalsIgnoreCase("exit")) {
	                    System.out.println(msg);
	                } else {
	                    System.exit(0);
	                }
	            }
	        } catch (Exception exp) {
	            exp.printStackTrace();
	        }
	    }
	}

Client.java

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

	public class Client {
	    Socket socket = null;


	    public Client() {
	        try {
	            socket = new Socket("localhost", 4444);
	            new ClientThread(socket);
	        } catch (UnknownHostException exp) {
	            exp.printStackTrace();
	        } catch (IOException exp) {
	            exp.printStackTrace();
	        }
	    }

	    public static void main(String[] args) {
	        new Client();
	    }
	}