0

I am developing a client for a small game. Using sockets, I am parsing the request and responses with PrintWriter and BufferedReader classes.

The issue I have is when BufferedReader is used for the second time (second response from server).

Example:

public class BotClient {

private final Socket socket;
private final PrintWriter writer;
private final BufferedReader reader;

public BotClient(final String gameId, final String botName) throws IOException {
    this.writer = new PrintWriter(socket.getOutputStream(), true);
    this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}

//Code that connects client to server. Works successfully.

public void sendGameRequest() {

try { 
    //This first is the FIRST request to server. This works SUCCESSFULLY.
    writer.println("GET " + "/playerInfo/?gameId=" + gameId + "&playerName=" + botName + " HTTP/1.0\r\n");

    reader.lines().forEach(System.out::println); // This will output game response successfully.

    //Now the problem occurs below here. I could do the same request but won't get an output.

    writer.println("GET " + "/playerInfo/?gameId=" + gameId + "&playerName=" + botName + " HTTP/1.0\r\n");

    reader.lines().forEach(System.out::println); //EMPTY PRINT

    // The above is EXACTLY the same request however this prints out nothing.

What could be the issue here and what is the best way to solve this problem?

bob9123
  • 725
  • 1
  • 9
  • 31

4 Answers4

0

Analysis

I suppose that the second writer.println() method call is not going to happen, because the statement:

reader.lines().forEach(System.out::println);

describes reading the lines from the stream, while the end of the stream (i.e. when the socket is closed) is not reached.

0

As i see, it is a HTTP request:

writer.println("GET " + "/playerInfo/?gameId=" + gameId + "&playerName=" + botName + " HTTP/1.0\r\n");

It could be that after the first request the connection was closed by remote pear. So, each time that you send a request you should open the connections, send the request, wait and receive the response and close the socket.

This is an extractor from the book: Http Definitive Guide by David Gourley and Brian Totty. enter image description here

Before send the second request check if the socket is open, if not, open it again and repeat the processes to send a request.

Jorge Omar Medra
  • 978
  • 1
  • 9
  • 19
  • Is it possible to open the same socket after you close it? I thought that it's not possible. – bob9123 Nov 18 '17 at 12:30
  • This answer could help you too: https://stackoverflow.com/questions/9794559/client-reconnect-java-socket It describe another way to detect when socket was closed and reconnect it. – Jorge Omar Medra Nov 18 '17 at 15:05
  • Do you guys recommend this approach of closing /reconnecting a socket for the my use case? Or is there a more efficient way to tackle the problem – bob9123 Nov 18 '17 at 15:48
  • @bob9123 i was wrong, according with documentation it’s not possible reconnect a socket that was closed. So, answer your comment you should use a new socket each time to send a request. https://stackoverflow.com/questions/8465394/how-to-correctly-close-a-socket-and-then-reopen-it – Jorge Omar Medra Nov 18 '17 at 23:38
  • This is the doc of Oracle where you can see the close specification: https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#close() – Jorge Omar Medra Nov 18 '17 at 23:42
0

reader.lines() is just providing a streamed view that is equivalent to calling reader.readLine() repeatedly, until the end of the file is reached. Once you have read the entire stream, there are no more lines to read.

You will need to store the lines. The easiest way to do this is to collect them into a List:

List<String> lines = reader.lines().collect(Collectors.toList());
lines.forEach(System.out::println);

A warning about InputStreamReader: Since you provided no charset, it will use the system’s default charset. This means your code will run differently on Windows than it does on other operating systems; a Windows machine probably will not be able to communicate with a non-Windows machine.

To make it run identically on all systems, specify an explicit charset:

    this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
VGR
  • 40,506
  • 4
  • 48
  • 63
0

Documentation says

The reader must not be operated on during the execution of the terminal stream operation. Otherwise, the result of the terminal stream operation is undefined. After execution of the terminal stream operation there are no guarantees that the reader will be at a specific position from which to read the next character or line.

LifeStyle
  • 411
  • 2
  • 10
  • How does this apply to my scenario? My second request happens after the terminal operation and not during. – bob9123 Nov 20 '17 at 03:34
  • You didnt close the input stream after first iteration. close it and open new one. – LifeStyle Nov 20 '17 at 09:08
  • So for every request I make I have to use a new socket? – bob9123 Nov 20 '17 at 18:21
  • new instance of stream not socket. but do not forget to close it before using new one – LifeStyle Nov 20 '17 at 19:11
  • So after my first forEach, I do reader.close(). Then if I want to read another response I do new reader = BufferedReader(new InputStreamReader(socket.getInputStream()) again? This should work? – bob9123 Nov 20 '17 at 20:13