João Vilaça
João Vilaça

Reputation: 621

Java erlang socket communication

i'm having trouble with the socket reading and writing through threads. The server's in erlang and the client in Java. The way i'm doing it is this:

PrintWriter printer = new PrintWriter(socket.getOutputStream(), true);
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
TransmitterTwo trans = new TransmitterTwo(socket);
trans.start(); // Gets the message from socket

TransmitterTwo Class:

public class TransmitterTwo extends Thread {
Socket socket;
String message;

TransmitterTwo(Socket socket) {
  this.socket = socket;
}

public String getMessageFromSocket() {
  return message;
}

public void run() {
  try {
    String response = null;
    BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  while ((response = reader.readLine()) != null) {
    System.out.println("Server response: "+ response);
    this.message = response;
  }

  socket.close();
} catch(IOException e) {
  e.printStackTrace();
}
}
}

The Problem is in the main client class. The idea is to: receive input from the console, send it to the socket, the server handles the logic and sends a response through the socket. Then on this client I check the response and do whatever i need to do. It's a registration flow, i register, i receive "register_ok", then i login...etc etc. The part of the loop where i'm having trouble is this:

while(true) {
  String readerInput = reader.readLine(); // Read from console
  printer.println(readerInput.trim()); // Sends it to the socket

  while(trans.message == null);
  socketMessage = trans.message;

Is this the right approach? The problem is that 'socketmessage' prints the previous received message, it's like..1 step behind, obviously this is thread related but I can't figure out the problem....help? Thanks

Upvotes: 0

Views: 160

Answers (1)

John H
John H

Reputation: 712

Your current approach is suboptimal because you're wasting your main thread spinning waiting on that variable to be updated. Because of how memory visibility works in java it may appear to never be updated (even if it actually is), or you may get stale values when you do access that variable. A more robust approach would be to pass messages between the threads using some of the built in collections in java:

public static void main(String[] args) {
    // This queue will be the link between the threads where 
    // they can pass messages to each other
    BlockingQueue<String> messages = new LinkedBlockingQueue<>();

    PrintWriter printer = new PrintWriter(socket.getOutputStream(), true);
    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    TransmitterTwo trans = new TransmitterTwo(socket, queue);
    trans.start(); // Gets the message from socket

    ...

    while(true) {
          String readerInput = reader.readLine(); // Read from console
          printer.println(readerInput.trim()); // Sends it to the socket

          // Wait for the other thread to push a message in to the queue.
          String recv = messages.take();
    }
}

public class TransmitterTwo extends Thread {
    final Socket socket;
    final BlockingQueue<String> queue;

    TransmitterTwo(Socket socket, BlockingQueue<String> queue) {
        this.socket = socket;
        this.queue = queue;
    }

    public void run() {
        try {
            String response = null;
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while ((response = reader.readLine()) != null) {
                System.out.println("Server response: " + response);
                // Add the response from the server to the queue
                queue.add(response);
            }

            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

This approach will never get stale values, and the take() operation on the main thread will block until there is some response from the server.

Upvotes: 1

Related Questions