2013-03-07 24 views
3

Я не смог найти удовлетворительный ответ на этот вопрос в любом месте. Объясните это кому-нибудь с пониманием внутренних дел?Первая запись в удаленно закрытый разъем не вызывает исключение, не так ли? Java

Я написал простой клиент/сервер, чтобы продемонстрировать эту проблему. Сервер считывает одну строку текста, затем закрывает сокет. Клиент пишет одну строку текста, ждет 10 секунд, затем записывает еще две строки текста. Вторая запись (через 10 секунд) терпит неудачу, но первая запись всегда преуспевает.

Почему BufferedWriter не генерирует исключение при первой записи? Ведь розетка обычно закрывалась долго. Код также считывает сокет прямо перед первой записью, возвращает -1, чтобы показать, что входная сторона уже обнаружила, что сокет закрыт. Почему выходная сторона также не может это знать?

public class Server { 
    public static void main(String[] args) throws IOException { 
     ServerSocket ss = new ServerSocket(9000); 
     Socket s = ss.accept(); 
     BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); 
     System.out.println(in.readLine()); 
     s.close(); 
     System.out.println("Socket closed"); 
    } 
    } 

    public class Client { 
    public static void main(String[] args) throws IOException, InterruptedException { 
     Socket s = new Socket("localhost", 9000); 
     BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); 
     out.write("Hello, World!\n"); out.flush(); 
     Thread.sleep(10000); 
     System.out.println("Read from socket returns: " + s.getInputStream().read()); 
     out.write("First write\n"); out.flush(); 
     System.out.println("First write succeeded without detecting socket closed"); 
     out.write("Second write\n"); out.flush(); 
     System.out.println("Second write succeeded without detecting socket closed"); 
    } 
    } 
+0

Просто потому, что сокет был закрыт программой, это не значит, что он был закрыт ОС. Пока клиент не получит ответ от базовых систем, что порт ушел, он предполагает, что все хорошо. Вот почему у нас есть протоколы и таймауты. – KevinDTimm

+0

Вы правы, я сменил ожидание на 5 минут, и первая запись вызывает исключение. Таким образом, это, вероятно, какой-то тайм-аут, несмотря на нормальную близкую последовательность; должно быть способом, которым ОС управляет сокетами. –

+0

На самом деле это отвечает на мой вопрос: http://stackoverflow.com/questions/2165670/is-it-possible-to-close-java-sockets-on-both-client-and-server-sides?rq=1 –

ответ

2

Удаленное закрытие неотличимо от удаленного выключения для выхода. Этот конец получает FIN в обоих случаях, что означает, что партнер прекратил отправку. Нет никаких признаков того, что он прекратил получать, даже на самом деле, если он отключился для ввода. Таким образом, единственный способ обнаружения отправителя - получить RST при отправке, и это не может произойти при первой отправке по определению, если, возможно, отправленные данные больше, чем буфер отправки сокета.

0

мы посмотрели на это по проекту. Я придерживаюсь мнения, что более или менее гарантированный сокет TCP/IP будет делать это.

IP-протокол предназначен для обеспечения наилучшего возможного маршрутизации пакета. Вы только когда-нибудь узнаете, что соединение не было на другом конце после того, как не удалось выполнить запись/доставку. Помня о том, что интернет был спроектирован так, чтобы быть устойчивым и пробовать разные маршруты и т. Д., Чтобы получить сообщение.

Различные транспортные сети и передачи данных могут работать по-разному. Долгое время назад мне приходилось делать сеансовый слой поверх tcp/ip, и эта проблема звучит странно знакомой.

Кажется, что вы можете обойти его, отправив пару тестовых байтов перед отправкой основного сообщения.