I spent some time tracking the code, and the problem is certainly a defect in the Scanner class.
public boolean hasNext() { ensureOpen(); saveState(); while (!sourceClosed) { if (hasTokenInBuffer()) return revertState(true); readInput(); } boolean result = hasTokenInBuffer(); return revertState(result); }
hasNext() calls hasTokenInBuffer()
private boolean hasTokenInBuffer() { matchValid = false; matcher.usePattern(delimPattern); matcher.region(position, buf.limit()); // Skip delims first if (matcher.lookingAt()) position = matcher.end(); // If we are sitting at the end, no more tokens in buffer if (position == buf.limit()) return false; return true; }
hasTokenInBuffer() always skips the first delimiter if it exists, as described in javadoc.
The next () and hasNext () methods and their primitive type methods (such as nextInt () and hasNextInt ()) first skip any input matching the delimiter pattern, and then try to return the next token. Both hasNext and the following methods can block waiting for further input. Regardless of whether the hasNext block blocks the method, whether its associated next method will be blocked.
First, we will skip the token that was still in the buffer from the last request, then we notice that we do not have new data in our buffer, so we call readInput() , in this case just \n , then we will loop back to hasTokenInBuffer() , which again will skip our delimiter!
At this point, the Server expects more input, and the Client expects a response. Dead end.
This can easily be avoided if we check to see if we missed the last token ...
private boolean skippedLast = false; private boolean hasTokenInBuffer() { matchValid = false; matcher.usePattern(delimPattern); matcher.region(position, buf.limit()); // Skip delims first if (!skippedLast && matcher.lookingAt()) { skippedLast = true; position = matcher.end(); } else { skippedLast = false; } // If we are sitting at the end, no more tokens in buffer if (position == buf.limit()) return false; return true; }