У меня очень странная проблема с классом Scanner
. Я использую Scanner
для чтения сообщений от Socket
со специальным токеном EOF. Все работает нормально, если клиент сразу записывает все запросы или запросы имеют данные, но операция блокировки hasNext()
зависает на сервере, а клиент, когда сообщения пишутся в кусках и следующий токен, должен быть пустой строкой ,java.util.Scanner зависает hasnext()
Что может вызвать это? Как я могу избежать этого?
Вот упрощенная версия того, что я пытаюсь сделать, \n
используется для тестирования, предположим, что разделителем может быть любая строка.
код сервера:
ServerSocketChannel serverChannel = null;
try {
serverChannel = ServerSocketChannel.open();
ServerSocket serverSocket = serverChannel.socket();
serverSocket.bind(new InetSocketAddress(9081));
SocketChannel channel = serverChannel.accept();
Socket socket = channel.socket();
InputStream is = socket.getInputStream();
Reader reader = new InputStreamReader(is);
Scanner scanner = new Scanner(reader);
scanner.useDelimiter("\n");
OutputStream os = socket.getOutputStream();
Writer writer = new OutputStreamWriter(os);
while (scanner.hasNext()) {
String msg = scanner.next();
writer.write(msg);
writer.write('\n');
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (serverChannel != null) {
try {
serverChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Рабочий Клиент:
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress("localhost", 9081));
InputStream is = socket.getInputStream();
Reader reader = new InputStreamReader(is);
Scanner scanner = new Scanner(reader);
scanner.useDelimiter("\n");
OutputStream os = socket.getOutputStream();
Writer writer = new OutputStreamWriter(os);
writer.write("foo\n\nbar\n");
writer.flush();
System.out.println(scanner.next());
System.out.println(scanner.next());
System.out.println(scanner.next());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
висячие Клиент:
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress("localhost", 9081));
InputStream is = socket.getInputStream();
Reader reader = new InputStreamReader(is);
Scanner scanner = new Scanner(reader);
scanner.useDelimiter("\n");
OutputStream os = socket.getOutputStream();
Writer writer = new OutputStreamWriter(os);
writer.write("foo\n");
writer.flush();
System.out.println(scanner.next());
writer.write("\n");
writer.flush();
System.out.println(scanner.next());
writer.write("bar\n");
writer.flush();
System.out.println(scanner.next());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Я закрываю канал сокета после ввода всех считаны, это неявно закрывает основной сокет (ы) , независимо от того, какая программа зависает задолго до того, как сокет должен быть закрыт. Токен используется как разделитель сообщений, поэтому несколько сообщений могут быть отправлены в течение одного сеанса, это не значит, что вы обнаруживаете конец потока.Я знаю, что конец потока приведет к возврату функции hasNext(). –
Пожалуйста, помните, что это всего лишь пример для воспроизведения проблемы, производственный код на самом деле использует неблокирующий сокетный канал, постоянно принимает соединения и порождает рабочие потоки для обработки чтения, записи и закрытия сокетов. –