0

I am trying to create an application where my client program reads the message from echo server. I'm trying to use Future to read the message from the server that will have a larger size than my allocated bytebuffer. My thought is to read into a outputstream until end-of-stream. However I think the code will stuck at readBytes = socket.read(buffer).get() at the last try becuase there will be nothing left to read from the socketchannel and Future will be blocked here. Please let me know how to fix this or another way around.

public String receiveMessage(){
    String message = "";
    if (socket.isOpen()) {
        try {
            ByteBuffer buffer = ByteBuffer.allocate(2);
            Future<Integer> readResult = socket.read(buffer);
            int readBytes = readResult.get();
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            while (readBytes != -1) {
                outputStream.write(buffer.array());
                buffer.clear();
                readBytes = socket.read(buffer).get();//stuck at here 
            }
            byte result[] = outputStream.toByteArray();
            System.out.println(result);
            message = new String(result, Charset.defaultCharset()).trim();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    return message;
}

'''

  • Once this method calls `socket.read().get()` it is no longer doing asynchronous I/O. If you want to read this way it is difficult to see why you started with asynchronous I/O at all. Just use `Socket` and its streams. – user207421 Jun 28 '22 at 23:29
  • @user207421 Thank you for the tip. However I would need to use asynchronous I/O for this project. Do you know how to perform read properly in this case? Should I use a completionhandler instead? – Raymond Hou Jun 28 '22 at 23:46
  • I would have thought they would want you to use callbacks rather than `Futures`, which would illustrate the underlying techniques a lot better. – user207421 Jun 29 '22 at 04:59

1 Answers1

-1

As this is an assignment, I believe I am not supposed to provide a completely functional answer, but here are some hints to guide you:

Oracle has many great Java tutorials including the one on sockets.

For asynchronous execution, I recommend creating a new java.lang.Thread object. Threads and Concurrency (unsurprisingly) also has a tutorial by Oracle. You may have something like the following, which I found useful when experimenting with Java sockets.

// write to server
Socket socket = //...
String message = //...
try (PrintWriter writer = new PrintWriter(socket.getOutputStream(), false)) {
    writer.println(message);
    // will auto-flush on '\n' (newline character) if 'false' in constructor is changed to
    // true or omitted (look at PrintWriter documentation)
    writer.flush();
} catch (IOException ioe) {
    ioe.printStackTrace();
}

// read from server
Socket socket = //...
try (BufferedReader reader = new BufferedReader(new InputReader(socket.getInputStream()))) {
    // TODO
} catch (IOException ioe) {
    ioe.printStackTrace();
}

// pipe input stream to output stream
// Perhaps you want what comes from the server to go directly into stdout
Socket socket = //...
new Thread() {
    @Override
    public void run() {
        try {
            socket.getInputStream().transferTo(System.out);
            // socket input stream is at end of stream, but not necessarily closed
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}.start();

Note that using InputStream#transferTo(OutputStream) will not terminate until the InputStream is closed, which is why you might want to execute it in its own thread.

Also, be careful about the above code segment: if you send a message through a socket using a PrintWriter then immediately close the PrintWriter, the PrintWriter will try to close the underlying OutputStream. Once that closes, it will generally try to close the Socket (whose OutputStream was being written to by the PrintWriter), and no more communication can be done through that socket (which will lead to a BrokenPipeException on attempted further use). So, perhaps try to send a message using newline characters as delimiters or something similar, which would be convenient for using a BufferedReader.

ReubenBeeler
  • 142
  • 1
  • 10
  • OP is required to use Asynchronous I/O. See the comments. And `PrintWriter` won't merely *try* to close the output stream and socket: it *will* close them, unless they are already closed or an exception occurs: and further use will lead to a 'socket closed' exception, not a 'broken pipe'. – user207421 Jun 29 '22 at 05:01
  • What is OP? I recall getting both types of exceptions, although I don't exactly remember what caused the broken pip exception. Also, `PrintWriter` does not necessarily close for reasons you stated, and because I am not well acquainted with them, I thought there may be other reasons. Regardless, if it will close the stream, then it will definitely try to close the stream, but not necessarily vice versa, so saying that it will try to close the stream is not incorrect. – ReubenBeeler Jun 29 '22 at 19:26