BufferedReader readLine() блокирует
При получении данных с использованием readLine(), хотя я помещаю "\n" в конце сообщения, используя.flush при отправке сообщения, цикл while, который читает мое сообщение, все еще блокируется. Только при закрытии сокета соединение выходит из цикла.
Вот код клиента:
bos = new BufferedOutputStream(socket.
getOutputStream());
bis = new BufferedInputStream(socket.
getInputStream());
osw = new OutputStreamWriter(bos, "UTF-8");
osw.write(REG_CMD + "\n");
osw.flush();
isr = new InputStreamReader(bis, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String response = "";
String line;
while((line = br.readLine()) != null){
response += line;
}
и код сервера:
BufferedInputStream is;
BufferedOutputStream os;
is = new BufferedInputStream(connection.getInputStream());
os = new BufferedOutputStream(connection.getOutputStream());
isr = new InputStreamReader(is);
String query= "";
String line;
while((line = br.readLine()) != null){
query+= line;
}
String response = executeMyQuery(query);
osw = new OutputStreamWriter(os, "UTF-8");
osw.write(returnCode + "\n");
osw.flush();
Мой код блокируется на сервере во время цикла. Благодарю.
6 ответов
BufferedReader будет продолжать читать ввод, пока не достигнет конца (конец файла, потока или источника и т. Д.). В этом случае "конец" - это закрытие сокета. Таким образом, пока соединение Socket открыто, ваш цикл будет выполняться, а BufferedReader будет просто ожидать ввода большего количества данных, повторяя цикл при каждом достижении '\n'.
Я перепробовал много решений, но нашел только одно, которое не блокировало выполнение:
BufferedReader inStream = new BufferedReader(new
InputStreamReader(yourInputStream));
String line;
while(inStream.ready() && (line = inStream.readLine()) != null) {
System.out.println(line);
}
inStream.ready()
возвращает false, если следующий readLine()
вызов заблокирует выполнение.
Это из-за условия в цикле while: while((line = br.readLine()) != null)
Вы читаете строку на каждой итерации и оставляете цикл, если readLine возвращает null
,
readLine возвращает только null, если eof достигнут (= socked закрыт) и возвращает String, если читается '\n'.
если вы хотите выйти из цикла в readLine, вы можете опустить весь цикл while и просто сделать:
line = br.readLine()
Было бы лучше избегать использования readline()
. Этот метод опасен для сетевых коммуникаций, потому что некоторые серверы не возвращаютLF/CR
символы, и ваш код застрянет. Когда вы читаете из файла, это не критично, потому что вы все равно дойдете до конца файла, и поток будет закрыт.
public String readResponse(InputStream inStreamFromServer, int timeout) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(inStreamFromServer, Charsets.UTF_8));
char[] buffer = new char[8092];
boolean timeoutNotExceeded;
StringBuilder result = new StringBuilder();
final long startTime = System.nanoTime();
while ((timeoutNotExceeded = (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) < timeout))) {
if (reader.ready()) {
int charsRead = reader.read(buffer);
if (charsRead == -1) {
break;
}
result.append(buffer, 0, charsRead);
} else {
try {
Thread.sleep(timeout / 200);
} catch (InterruptedException ex) {
LOG.error("InterruptedException ex=", ex);
}
}
}
if (!timeoutNotExceeded) throw new SocketTimeoutException("Command timeout limit was exceeded: " + timeout);
return result.toString();
}
У него есть тайм-аут, и вы можете прервать общение, если это займет много времени
Это происходит потому, что InputStream не готов быть красным, поэтому он блокирует in.readLine() . Пожалуйста, попробуйте это:
boolean exitCondition= false;
while(!exitCondition){
if(in.ready()){
if((line=in.readLine())!=null){
// do whatever you like with the line
}
}
}
Конечно, вы должны контролировать условие выхода.
Другим вариантом может быть использование пакета nio, который позволяет асинхронное (не блокирующее) чтение, но это зависит от ваших потребностей.
Если вы хотите получить содержимое сокета без необходимости его закрытия, просто используйте ObjectInputStream и ObjectOutputStream .
Пример:
ObjectInputStream ois;
ObjectOutputStream oos;
ois = new ObjectInputStream(connection.getInputStream());
String dataIn = ois.readUTF(); //or dataIn = (String)ois.readObject();
oos = new ObjectOutputStream(connection.getOutputStream());
oos.writeUtf("some message"); //or use oos.writeObject("some message");
oos.flush();
.....
readline() и read() будут заблокированы, пока сокет не закроется. Поэтому вы должны закрыть сокет:
Socket.shutdownInput();//after reader
Socket.shutdownOutput();//after wirite
а не Socket.close();