0

I'm new with Java and I'm trying to learn threads and socket. So decide to make simple client-server application following official java tutorial. My idea is simple - server wait for connection, if appears, it makes new thread with new socket, input and output. Client side -> make connection; new thread with socket, input, output and stdIn (to read line and after that send it to the server). But something is wrong (don't have any idea why) with my code. The connection is established, there's no exceptions. Could someone explain why doesn't work and how to fix it? Also could you have any suggestions about the code (probably it's not with best practices and things like that):

Client side:

public class Client {
    private BufferedReader reader;
    private Socket sock;
    private PrintWriter writer;

public static void main(String[] args) {
    Client client = new Client();
    client.go();
}

public void go() {
    setUpNetworking();

}

private void setUpNetworking() {
    try{
        sock = new Socket("127.0.0.1", 5000);
        System.out.println("Network established");

        ServerThread serverThread= new ServerThread(sock);
        serverThread.start();

        System.out.println("Type your message: ");
    } catch (IOException e) {
        System.out.println("Problem with establishing the network: " + e);
    }
}

class ServerThread extends Thread {
    Socket socket;
    PrintWriter out;
    BufferedReader in;
    BufferedReader stdIn;

    ServerThread(Socket socket) {
        this.socket = socket;

        try{
            out = new PrintWriter(socket.getOutputStream());
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            stdIn = new BufferedReader(new InputStreamReader(System.in));
        }catch (IOException e) {
            System.out.println("Problem with trying to read/write to server: " + e);
        }
    }
    @Override
    public void run() {
        String fromServer;
        String fromClient;
        while(true){
            try{

                if((fromServer = in.readLine()) != null) System.out.println(" " + fromServer);
                else if((fromClient = stdIn.readLine()) != null) out.println(fromClient);

            }catch(Exception e) {
                System.out.println("msg exception: " + e);
            }

        }
    }
}

}

Server side:

public class Server {
    //Run server until keepGoing = false
    private boolean keepGoing = true;



    public static void main(String[] args) {
        Server server = new Server();
        server.go();
    }

    public void go() {

            try {
                ServerSocket serverSocket = new ServerSocket(5000);

                while(keepGoing) {

                    Socket clientSocket = serverSocket.accept();
                    ClientThread t = new ClientThread(clientSocket);
                    t.start();
                }
            } catch (IOException e) {
                System.out.println("Problem with socket/network: " + e);
            }
    }

    class ClientThread extends Thread {
        Socket clientSocket;
        PrintWriter out;
        BufferedReader in;

        ClientThread(Socket clientSocket) {
            this.clientSocket = clientSocket;

            try{
                out = new PrintWriter(clientSocket.getOutputStream());
                in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            } catch (IOException e) {
                System.out.println("Problem with creating in/out: " + e);
            }
        }

        @Override
        public void run() {
            String message;
            while(keepGoing) {
                try{
                    message = in.readLine();
                    out.println(message);
                    System.out.println(message);

                } catch (IOException e){
                    System.out.println("Exception while try to read line: " + e);
                }

            }
        }
    }

}

PS I've changed a bit the code - instead of made ClientThread Class, I made new runnable class and pass that variable to thread class. Inspired by this question: "implements Runnable" vs. "extends Thread".

Community
  • 1
  • 1
Georgi Stoyanov
  • 469
  • 1
  • 5
  • 24

1 Answers1

1

I think the problem is that both server and client are waiting for any input. Server:

message = in.readLine();

Client:

if((fromServer = in.readLine()) != null)
   System.out.println(" " + fromServer);
else if((fromClient = stdIn.readLine()) != null)
   out.println(fromClient);

But the client code already blocks on the fromServer = in.readLine() part, so it never gets to read from standard in, and thus nothing will be sent out to the server.

You could move your attempt to read from standard in to the setUpNetworking method, right after the System.out.println("Type your message: ");. Build a loop there which you exit if the user types "exit" or "quit" or something like that:

BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String read = "";
do {
    read = stdIn.readLine();
    System.out.println("Read from stdin: " + read);
    serverThread.send(read);

}
while (!read.equals("exit"));

The ServerThread.send() method is simple:

void send(String string) {
    System.out.println("Sending to server: " + string);
    out.println(string);
}

However, to make it work, you either have to flush the stream manually after writing to out, or use the following constructor:

out = new PrintWriter(socket.getOutputStream(), true);

See the PrintWriter's JavaDoc: True means auto-flush on newline.

I tested this setup and it worked for me. I was able to send something from the client to the server.

However, this is only the first step. I would implement both reading and writing as separate threads, for both client and server. And there is no graceful shutdown of sockets implemenented yet. A more complete yet simple example can be found on Oracle.

beosign
  • 433
  • 5
  • 10
  • Sry but seems like if i didn't get what to do or doesn't work that way :/ It sounds very easy to work with threads and sockets, but it's really hard for me :/ – Georgi Stoyanov Aug 30 '15 at 21:49
  • No prob, but I need some more input to further assist you. 1) Did you try to move the `fromServer = in.readLine()` line and did it work afterwards? I will edit my answer to be more verbose here. 2) Where are your exact problems with threading/sockets? It is easier to help if you have more specific questions. – beosign Aug 31 '15 at 06:48
  • I've tried to change lines and make it this way: `if((fromClient = stdIn.readLine()) != null) out.println(fromClient); if((fromServer = in.readLine()) != null) System.out.println(" " + fromServer);` and doesn't work either. I think that the problem really is in listening for events, but can't find where. Maybe can't use debugger right way, but in the client side know everything is ok - I'm typing to out, and then at second if checking for incoming stream nothing happens. Can't view if my stream goes to server and then back to client :/ – Georgi Stoyanov Aug 31 '15 at 07:02
  • That's because of the missing flush, see edited answer above :) – beosign Aug 31 '15 at 07:11