powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / IO/NIO WTF
25 сообщений из 85, страница 3 из 4
IO/NIO WTF
    #38416609
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zalexakaBlazkowicz…
Вот в этом примере 14921347 , по логике один из двух pump может заблокироваться, так как данные в эту сторону уже не идут.
И второй pump не вызовется. Ведь поток заблокирован.
Но на практике этого не происходит.

И в catch не попадает при этом?
Не понял вопроса. Вышеприведенный код отлично работает. Выкидывает исключения, когда комуникация завершена и это нормально.

Вопрос в том, что если клиент шлет один пакет. Сервер шлет второй и третий. Но, после 2го пакета, метод должен блокироваться на чтении из клиента. Но клиент ничего не шлет. Ждет третьего пакета с сервера. А третий пакет не передаётся, потому что поток заблокирован. Почему этого не происходит?
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38416626
zalexaka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,
Упс, тупанул вопрос действительно не в тему.
BlazkowiczПочему этого не происходит? Возможно pump прокачивает пакеты по одному, других объяснений не нахожу.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38416689
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczЕщё удивительно то что абсолютно аналогичный код на NIO API отрабатыват. Там нет available, но там и лишний read не приводит к RST.
В исходниках SocketInput/OuputStream очень много проверок на isReset[Pending]. Видимо в nio проверки иначе. Но все равно без закрытия на другой стороне RST просто так возникнуть все же не может.
BlazkowiczСпасибо. Не знал. А почему бы просто не закрыть клиенту соединение тогда? Или это такой способ для одной стороны сообщить другой, что она планово закрылась? Помогите понять суть RST. Ткните носом в нужный мануал, что ли.
Если нужно закрывать только убедившись, что другая сторона прочитала данные, то можно сделать следующим образом.
На стороне, которая хочет инициировать закрытие.
Код: java
1.
2.
3.
4.
socket.shutdownOutput();//закрытие исходящего потока. также инициирует протокол закрытия этого сокета.
int n = socket.read();//ждем получения подтверждения о том, что соединение было закрыто на той стороне.
assert n == -1;//EOF
socket.close();


А другой cтороне
Код: java
1.
2.
3.
4.
int n = socket.getInputStream().read();
if (n == -1) {//EOF другая сторона закрыла сокет.
  socket.close();
} else  ... // обычный случай когда получили данные.


Или сделать специальное сообщение, которое будет говорить другой стороне, что после его получения надо бы завершить соединение.

А про мануал - Сетевое программирование в Unix Стивенса.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417273
DoSOfRedRiver
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

авторGoogle -> IO faster than NIO.
И когда дело доходить до многопоточности, мы проигрываем в производительности из-за концепции thread-per-connection. Дело случая.

авторКонкретику, пожалуйста. sendUrgentData() или какой ещё heartbeat?
В вашем случае думается только эксепшены ловить.

авторо на IO у меня не получается даже обычный протокол прокачать без защиты.
Попробуйте. Там рядом ещё многопоточная реализация была.

авторВозможно я не понимаю Blocking NIO.
http://stackoverflow.com/questions/17615272/java-selector-is-asynchronous-or-non-blocking-architecture

В качестве мультиплексора выступают селекторы.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417304
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DoSOfRedRiverИ когда дело доходить до многопоточности, мы проигрываем в производительности из-за концепции thread-per-connection. Дело случая.
Зависит исключительно от того на сколько эффективно ОС управляет потоками. Переключение контекста уже совсем не дорогая операция в современных системах.

DoSOfRedRiverВ вашем случае думается только эксепшены ловить.

available() не выкидывает исключения. А read() выкидывает его раньше времени. Так где мне его ловить?

DoSOfRedRiver Попробуйте. Там рядом ещё многопоточная реализация была.
Повторяю. Вот этот гениальный код не работает для 3rd party клиента, который конектиться к моему серверу.
Код: java
1.
while((bytes_read = from_server.read(reply)) != -1) 



DoSOfRedRiver http://stackoverflow.com/questions/17615272/java-selector-is-asynchronous-or-non-blocking-architecture
Там ни слова про configureBlocking(true) в NIO.

DoSOfRedRiverВ качестве мультиплексора выступают селекторы.
Холодно.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417368
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowiczavailable() не выкидывает исключения. А read() выкидывает его раньше времени. Так где мне его ловить?
так не выйдет?

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
    Socket s = new Socket("host", port);
    PushbackInputStream inStream = new PushbackInputStream(s.getInputStream());

    boolean isClosed(PushbackInputStream stream) {
        try {
            byte[] r = new byte[1];
            int result = stream.read(r);
            if (result > -1) {
                if (result > 0) {
                    stream.unread(r);
                }
                return false;
            }
            return true;
        } catch (SocketTimeoutException te) {
            return false;
        } catch (IOException ie) {
            return true;
        }
    }
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417369
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл...

Код: java
1.
2.
3.
    Socket s = new Socket("host", port);
    s.setSoTimeout(1);
    PushbackInputStream clientInStream = new PushbackInputStream(s.getInputStream());
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417383
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczПроблема в том что нет какого-то однозначно способа определить состояния и поступить правильно в зависимости от этого в IO. Сокет :
Привязан ?
Закрыт ?
Подключен ?
Клиент больше не пишет ?
Клиент больше не читает ?

Или что?
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417388
DoSOfRedRiver
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

авторТам ни слова про configureBlocking(true) в NIO.
Что? Там картинка даже есть специальная, Blocking I/O называется.

авторЗависит исключительно от того на сколько эффективно ОС управляет потоками. Переключение контекста уже совсем не дорогая операция в современных системах.
Да. Но когда дело доходит до высоко-нагруженных приложений, почему-то предпочитают Node.js, а не Апачи всякие.

авторavailable() не выкидывает исключения. А read() выкидывает его раньше времени. Так где мне его ловить?
А если в код вроде if ((read = in.read(buff)) > 0) трюкача поставить и на эксепшене закрывать соединение конечным адресатом?
Или вы про паузы во время передачи данных?
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417393
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczschwaДругая сторона нам отправила RST в ответ на нашу операцию записи.
У меня на чтение. Это и оказалось большим сюрпризом.Ошибки могут возникать в любой момент.
Если некто на любом участке между нами и ними уже знает, что райком закрыт и с фронта никто не вернулся, то есть всего три вариант:
1. Штатно закрыть подключение, прислав FIN-итный пакет и, возможно, соблюсти ещё какие-то формальности;
2. Тупо молчать, пока IP-стек не известит прикладуху о connection timeout;
3. Сбросить подключение прислав RST.

P.S. Стек сетевых ошибок нахер никому не нужен - он всегда один и тот же.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417459
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovBlazkowiczПроблема в том что нет какого-то однозначно способа определить состояния и поступить правильно в зависимости от этого в IO. Сокет :
Привязан ?
Закрыт ?
Подключен ?
Клиент больше не пишет ?
Клиент больше не читает ?
Или что?
Значения этих свойств одни и тоже на серверном сокете
- До начала чтения пакета с клиента.
- По окончании чтения пакета, до следующего чтения.
- И самое обидное: после исключения connection reset вызваного чтением.
То есть можно было бы поймать исключение, посмотреть свойства, что-то предпринять, а фигушки. Ни одно из этих свойств значения не меняет, когда даже в сокет нельзя ни читать, ни писать.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417468
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Андрей Панфиловтак не выйдет?

Я не понял чем это отличается от использования available() по поведению. На вскидку - тоже самое. Я также отхвачу исключение, при попытке чтения и тем самым "закрою" сокет на запись (клиент закроет его сам), которую мне ещё предстоит произвести.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417469
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хм-м-м ...
Надо будет поразвлекаться на досуге ...
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417472
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DoSOfRedRiverавторТам ни слова про configureBlocking(true) в NIO.
Что? Там картинка даже есть специальная, Blocking I/O называется.

Это картинка для классического IO, а не для Blocking NIO.

DoSOfRedRiverДа. Но когда дело доходит до высоко-нагруженных приложений, почему-то предпочитают Node.js, а не Апачи всякие.

Сотни леммингов не могут ошбаться.

DoSOfRedRiverА если в код вроде if ((read = in.read(buff)) > 0) трюкача поставить и на эксепшене закрывать соединение конечным адресатом?
"трюкача поставить"?

DoSOfRedRiverИли вы про паузы во время передачи данных?
Нет. Я про два примера кода в начале темы. Один - мой. Не работает, потому что read выкидывает исключения и клиент закрывает сокет. Второй Андрея Панфилова - работает нормально, но нет никакого признака, чтобы выйти из цикла.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417539
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

это не отличается от available, оно в дополнение - пока в буфере данные есть читаем available, если нет висим секунду на таймауте.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
public class Test implements Runnable {

    private Socket _i;
    private Socket _o;

    private Test(Socket i, Socket o) {
        _i = i;
        _o = o;
    }

    @Override
    public void run() {
        try {
            pump(_i, _o);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    static void pump(Socket i, Socket o) throws IOException {
        o.setSoTimeout(1);
        i.setSoTimeout(1);
        PushbackInputStream out = new PushbackInputStream(o.getInputStream());
        PushbackInputStream in = new PushbackInputStream(i.getInputStream());
        while (true) {
            while (in.available() > 0) {
                pump(in, o);
            }
            while (out.available() > 0) {
                pump(out, i);
            }
            if (checkClosed(in, o)) {
                o.close();
                break;
            }
            if (checkClosed(out, i)) {
                i.close();
                break;
            }
        }
    }

    static boolean checkClosed(PushbackInputStream in, Socket o)
        throws IOException {
        boolean closed = false;
        try {
            byte[] r = new byte[1];
            int result = in.read(r);
            if (result > -1) {
                if (result > 0) {
                    in.unread(r);
                }
            } else {
                closed = true;
            }
        } catch (SocketTimeoutException te) {
            // ignore
        } catch (IOException ie) {
            closed = true;
        } finally {
            try {
                if (in.available() > 0) {
                    pump(in, o);
                }
            } finally {
                if (closed) {
                    in.close();
                }
            }
        }
        return closed;
    }

    static void pump(InputStream s, Socket o) throws IOException {
        byte[] r = new byte[s.available()];
        s.read(r);
        o.getOutputStream().write(r);
    }

    public static void main(String[] argv) throws Exception {
        ServerSocket ss = new ServerSocket(22);
        Socket i = null;
        while ((i = ss.accept()) != null) {
            Socket o = new Socket("192.168.2.49", 22);
            new Thread(new Test(i, o)).start();
        }
    }
}
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417663
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот нормальный пример TCP-туннеля на блокирующем IO, один поток на сервер, один поток на клиент:
http://svn.apache.org/viewvc/webservices/tcpmon/trunk/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/Relay.java?view=markup
http://svn.apache.org/viewvc/webservices/tcpmon/trunk/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/TcpTunnel.java?view=markup

Когда я вижу, что два соединения сидят в одном потоке, как в примере выше, у меня едва ли не кровь из глаз идет, без шуток. Вот простейший пример, когда такой подход просто катастрофически неверен. Пишете вы, значит, такой клиент-серверную игру. Написали, и вот хотите посмотреть на то, какой трафик она генерирует. Подключаете свой "Пушбэк", и начинаете смотреть. Смотрите-смотрите, вроде все в порядке. Но в какой-то момент у вас начинается "война гильдий", и сервера начинает переть дофига траффика. И вы вдруг замечаете, что клиент перестал отсылать траффик на сервер. То есть игрок видит, что происходит, но сам ничего сделать не может. Отключаете свою тулзу - все в порядке. Подключаете опять - снова игрок ничего сделать не может. А в чем проблема? Да в том, что вы никак не можете выйти из цикла, если трафика слишком много:
Код: java
1.
2.
3.
while (out.available() > 0) {
    pump(out, i);
}



А что вы будете делать, если сервер устроен так, что вычитывает из клиента бинарные данные, и сериализует их в какой-нибудь условный ServerObject, но делает это до тех пор, пока не пример, скажем, 3 таких объекта, после чего перестает читать клиента, пока что-то не запишет в него? У вас опять все зависнет, теперь уже не в цикле, а внутри метода pump.

Про busy-loop я уже молчу, ибо уж этот косяк должен быть всем очевиден.

Поэтому я еще раз хочу заакцентировать внимание, что код, подобный этому 14927138 - это демонстрация того, как ни в коем случае нельзя организовывать TCP-туннели, особенно учитывая то, что мы тут стремимся выработать общее решение, которое будет работать для любых клиент-серверных протоколов.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417717
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjv,

Спасибо, К.О., до вас никто не знал, что двунаправленный канал лучше обрабатывать двумя потоками, осталось только понять как это относится к:

BlazkowiczWTF#1 - метод InputStream.available() бесполезен и даже сломан для сокетов.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417730
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Андрей Панфилов ,
Да точно так же, как и ваш код :-)
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417734
maxkar
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczschwaБез закрытия соединения на другой стороне RST получить никак нельзя.
Спасибо. Не знал. А почему бы просто не закрыть клиенту соединение тогда? Или это такой способ для одной стороны сообщить другой, что она планово закрылась? Помогите понять суть RST. Ткните носом в нужный мануал, что ли.

RST - это как раз не планово а аварийно. Ключевые слова - "tcp termination sequence". Можно еще по SO_LINGER поискать, там завершение TCP-сессии тоже подробно рассматривается (лингеринг - это ручная настройка tcp termination sequence). У вас клиент делает close без shutdown (или shutdown с SO_LINGER в 0), и это большая ошибка. Правильно было бы трясти производителя, чтобы закрытие поправили, а не искать workaround.

На пальцах картина примерно следующая (может быть, ошибаюсь где-то).

RST - это аварийное завершение соединения. Если OS получила RST, значит, на другой стороне сокета (пары от нашего локального) больше нет ни в каком виде. Т.е. удаленная OS о "сокете" ничего не знает. Типичное использование RST - в ответ на пришедший пакет. Вот стоит у вас машина, ничего плохого не делает, а ей вдруг приходит какой-то пакет "на порт 4321 от 8.8.9.9" и якобы "в середине текущего соединения". Вот на такой пакет ваша OS пошлет RST удаленной стороне. Удаленная сторона его получит (если получит) и прекратит посылать сообщения (те же повторные отправки пакетов из-за отсутствия подтвержднеия и т.п.).

Т.е. если мы получили RST, с сокетом уже ничего сделать нельзя. Нет второй стороны уже ни в каком виде (все последующие пакеты только RST в ответ и могут получить). Только открывать новый сокет.

Далее. Закрытие сокета без предварительного shutdown тоже приводит к RST. Т.е. вызов "socket.close() без socket.shutdownOutput()" - это аварийное завершение, при котором, в частности, не нужно гарантировать доставку уже отправленных пакетов (да, это именно так!). Поэтому ОС посылает RST и освобождает ресурсы сразу же. Все дальнейшие входящие пакеты (как данные, так и служебные) по данному сокету получат "RST" (все структуры данных от сокета уже освобождены). Логика в этом поведении есть. Приложение решило, что "клиент уже не тот" и дальше с ним общаться смысла нет. Соответственно, данные "неправильному" клиенту доставлять тоже не нужно, поэтому можно сокет (и все структуры данных) освободить сразу же.

С shutdownOuptut ситуация иная. Во-первых, вызов shutdown блокирующий и ожидает потверждения доставки всех данных от протиовоположной стороны (т.е. если что-то "не дошло", будет исключение). После shutdown и close сокет какое-то время остается в системной таблице в состоянии TIME_WAIT. В этом состоянии ОС отправляет подтверждения второй стороне о данных с нее. Нужно это, чтобы вторая (удаленная) сторона на свой socket.shutdown не получила ошибок. Пусть A - наша машина, (на ней мы сделали shutdown+close). Б - какая-то удаленная машина. Когда-то Б отправляла машине А данные. Машина А получила их, отправила подтвеждение, и это подтверждение потерялось. Т.е. с точки зрения машины А все хорошо. А с точки зрения машины Б - проблемы со связью. Поэтому Б будет какое-то время повторно посылать пакеты (retransmit). Если бы после close сокет удалялся из таблиц, машина A в ответ на retransmit послала бы RST (см. выше, это стандартный ответ если адресат не найден) и сторона Б считала бы, что данные не дошли. А так как сокет находится в TIME_WAIT, OS о нем знает и повторно отправляет подтверждение (тех данных, которые код на А уже давно обработал).

Так что если shutdown отсутствует, вторая сторона мало того что получит ошибку (в любом языке!), так еще и "последние отправленные данные" могут потеряться (потому что retransmit делать уже некому). И никаких гарантий о поведении второй стороны после RST уже нет.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417737
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maxkarДалее. Закрытие сокета без предварительного shutdown тоже приводит к RST. Т.е. вызов "socket.close() без socket.shutdownOutput()" - это аварийное завершение, при котором, в частности, не нужно гарантировать доставку уже отправленных пакетов (да, это именно так!).Нет, это не так. Читаем JavaDoc метода close():

JavaDocCloses this socket.
Any thread currently blocked in an I/O operation upon this socket will throw a SocketException.
Once a socket has been closed, it is not available for further networking use (i.e. can't be reconnected or rebound). A new socket needs to be created.
Closing this socket will also close the socket's InputStream and OutputStream.
If this socket has an associated channel then the channel is closed as well.
Более того, на первой странице я приводил пример. Вот его небольшая модификация:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
public class SocketExample {
    public static void main(String[] args) throws Exception {
        final byte[] chunk1 = new byte[] {1, 2, 3, 4};
        final byte[] chunk2 = new byte[] {5, 6, 7, 8};
        final byte[] chunk3 = new byte[] {9, 10, 11, 12};

        final CountDownLatch latch1 = new CountDownLatch(1);
        final CountDownLatch latch2 = new CountDownLatch(1);
        final CountDownLatch latch3 = new CountDownLatch(1);

        new Thread(new Runnable() {
            @Override public void run() {
                try {
                    ServerSocket srvSock = new ServerSocket(8844);

                    Socket cliSock = srvSock.accept();

                    OutputStream os = cliSock.getOutputStream();

                    os.write(chunk1);

                    latch1.await();

                    os.write(chunk2);

                    latch2.await();

                    os.write(chunk3);
                    cliSock.close();
                    srvSock.close();

                    latch3.await();
                }
                catch (Exception ignore) {
                    // Ignore.
                }
            }
        }).start();

        Thread.sleep(1000);

        Socket sock = new Socket("localhost", 8844);

        InputStream is = sock.getInputStream();

        assert is.available() == 4;

        byte[] buf = new byte[4];

        int read = is.read(buf);

        assert read == 4;
        assert Arrays.equals(buf, chunk1);
        assert is.available() == 0;

        latch1.countDown();
        Thread.sleep(50);

        assert is.available() == 4;

        read = is.read(buf);

        assert read == 4;
        assert Arrays.equals(buf, chunk2);
        assert is.available() == 0;

        latch2.countDown();
        Thread.sleep(50);

        assert is.available() == 4;

        read = is.read(buf);

        assert read == 4;
        assert Arrays.equals(buf, chunk3);
        assert is.available() == 0;

        latch3.countDown();
        Thread.sleep(50);

        assert is.read() == -1;
    }
}


Как видите, никакого RST в виде Exception не возникает.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417791
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Закрытие SocketOutput/InputStream-ов при вызове socket.close() в java не имеет никакого отношения к shutdownOutput, который является вызовом shutdown с флагом SHUT_WR. Т.к. close и shutdown это разные операции.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417924
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем, вот как это работает, например, на Windows.

Сначала читаем в MSDN статью о том, как делать gracefull shutdown сокета: http://msdn.microsoft.com/en-us/library/windows/desktop/ms738547(v=vs.85).aspx
Из этой статьи следует, что сокет можно вырубать двумя способами: shutdown() + closesocket() или WSASendDisconnect() + closesocket() .

Теперь смотрим на имлепементацию дефолтного джавовского дуал-сокета: http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/windows/native/java/net/DualStackPlainSocketImpl.c

Из него мы видим, что при вызове shutdown() из Java происходит вызов shutdown() в Windows.
А когда мы вызываем close() из Java, то это делегируется в http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/windows/native/java/net/net_util_md.c в метод NET_SocketClose, который в свою очередь вызывает как раз таки WSASendDisconnect() + closesocket() , как и написано в WinAPI.

Таким образом, Socket.close() является безопасным способом вырубать сокет. По крайней мере на Windows. Что и доказывает приведенный выше код.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417986
maxkar
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjvКак видите, никакого RST в виде Exception не возникает.
Здесь все еще хуже. Оно банально не работает:
Код: powershell
1.
2.
3.
4.
5.
6.
7.
8.
9.
maxkar@progressor ~/test/proxy $ java -ea SocketExample
Exception in thread "main" java.lang.AssertionError
	at SocketExample.main(SocketExample.java:51)
^Cmaxkar@progressor ~/test/proxy $ java -version
java version "1.7.0_40"
Java(TM) SE Runtime Environment (build 1.7.0_40-b43)
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)
maxkar@progressor ~/test/proxy $ uname -a
Linux progressor 3.10.7-gentoo-r1 #1 SMP Sun Sep 29 20:06:02 MSK 2013 x86_64 Intel(R) Core(TM) i7-2700K CPU @ 3.50GHz GenuineIntel GNU/Linux



Я еще немного поигрался с сокетами. В общем, "по-умолчанию" socket.shutdown делает все нормально на любом языке (с точки зрения удаленной стороны). В документации я не нашел, что такое поведение гарантируется. Так что shutdown желательно делать (он еще и ошибку даст, если какие-то данные не дошли). Но если "специально постараться", отправить RST не составит большого труда:

Сервер:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;

public class SE {
    public static void main(String[] args) throws Exception {
        final byte[] chunk1 = new byte[] {1, 2, 3, 4};

        try {
            ServerSocket srvSock = new ServerSocket(8844);
            Socket cliSock = srvSock.accept();

            Thread.sleep(1000);
            InputStream is = cliSock.getInputStream();

            assert is.available() == 4;
            byte[] buf = new byte[4];

            int read = is.read(buf);

            System.out.println(Arrays.toString(buf));
            assert read == 4;
            assert Arrays.equals(buf, chunk1);
            assert is.available() == 0;

            Thread.sleep(1000);

            assert is.read() == -1;

            cliSock.close();
            srvSock.close();

        }
        catch (Throwable ignore) {
          ignore.printStackTrace();
        }

    }
}


Клиент:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
import java.io.*;
import java.net.*;

public class SES {
  public static void main(String[] args) throws Exception {
    final Socket s = new Socket("localhost", 8844);
    final byte[] buf = {1,2,3,4};
    s.setSoLinger(true, 0);
    final OutputStream ss = s.getOutputStream();
    ss.write(buf);
    s.close();
  }
}



Сервер с ключиком -ea нужно запускать (это я с вашего примера брал).

Зачем стороннее приложение использует SO_LINGER? Ну не знаю. Может, оно тысячами в секунду соединения плодит и не хочет, чтобы эти сокеты висели в TIME_WAIT.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417993
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На Windows работает нормально. Где именно вылез assert? Что на SocketExample.java:51 строке?

А с SO_LINGER это некорректное рассуждение просто. Если вы его выставляете, значит для вас нормально, что другая сторона может получить RST.
...
Рейтинг: 0 / 0
IO/NIO WTF
    #38417996
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjvТаким образом, Socket.close() является безопасным способом вырубать сокет. По крайней мере на Windows. Что и доказывает приведенный выше код.
Нет. Но в конце этой статьи написано, что нужно сделать, чтобы закрыть "безопасно" нормально.
...
Рейтинг: 0 / 0
25 сообщений из 85, страница 3 из 4
Форумы / Java [игнор отключен] [закрыт для гостей] / IO/NIO WTF
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]