Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет yigal_s ([info]yigal_s)
@ 2012-10-17 17:09:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
шиза косила наши ряды
Во втором десятилетии третьего тысячелетия под виндами в сокетах, похоже, какой-то совершенно невменяемый баг -- клиент умудряется получить ошибку 10054, когда сервер закрывает TCP сокет.

В интернете по этому поводу идёт какое-то невнятное бурчание, толком ничего не нашел. Правда, на страничке http://msdn.microsoft.com/en-us/library/windows/desktop/ms737582(v=vs.85).aspx один в комментариях пишет, что "closesocket broken for graceful shutdown" правда сразу после этого ссылается на баг-репорт от Sun которые как раз жалуются, что в Виндах наоборот нет работает как раз "abortive close", т.е. опять шум, а не информация.

У меня тоже какая-то бредовая ситуация - часть тестов стабильно проходит, часть стабильно валится, и пока непонятно что именно приводит к проявлению бага. Но, разумеется, стабильность воспроизведения означает, что эту проблему я как-нибудь заломаю в константное время.


(Добавить комментарий)


[info]mavcan@lj
2012-10-17 23:55 (ссылка)
Не может быть, что клиенту приходит RST (то есть сервер просто сделал Socket.Close()) вместо FIN (Socket.Shutdown())?
У вас случайно не мобильные сети?

(Ответить) (Ветвь дискуссии)


[info]yigal_s@lj
2012-10-18 00:59 (ссылка)
тест бежит внутри одного компа, адрес 127.0.0.1 )))

Я использую обычный сокетовский Сишный интерфейс (ну не обычный, а виндовский).

Поправьте ежели что не так, но ПРОСТО закрытие сокета (close) без shutdown - совершенно нормальная операция, ведущая к FIN, а RST в ней будет посылаться только если для сокета включен linger (у меня вроде отключен).

Далее, прикол-то в том, что shutdown перед close я всё ж вызываю, закрывая одновременно и передачу и приём.

А вот чинится это (если это действительно починка будет, в чем я пока не убедился) вызовом shutdown закрывающего ТОЛЬКО передачу. И вся эта морока происходит исключительно под виндами, под линуксом проблем нет.

ПС: только воспроизводить не пытайтесь, я еще не понял всех условий, приводящих к данной проблеме

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]mavcan@lj
2012-10-18 09:25 (ссылка)
TCP достаточно сложен, чтобы разные реализации вели себя по-разному.
Ну вообще-то да, это неправильно шатдаунить соединение с двух сторон сразу. Это как если бы мы с вами разговаривали, и одновременно сказали друг другу "пока". Одна сторона (любая!) решает, что пора заканчивать, а вторая - только подтверждает (FIN+ACK).

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]yigal_s@lj
2012-10-18 11:21 (ссылка)
ну почему же, если я как сервер получил запрос и послал ответ, я могу себе позволить закрывать обе стороны соединения, ибо запрос я прочитал полностью, полностью выдал на него ответ и более ничего читать по тому же сокету не собираюсь.

Вторая сторона (клиент) в любом случае получит нулевой блок на чтении, поймёт, что поток данных закончился и со своей стороны тоже вызовет close, что приведёт ко второму FIN.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]mavcan@lj
2012-10-18 11:52 (ссылка)
Нет-нет, вы меня не так поняли.

Socket.Close() надо вызывать вообще всегда; это освобождение ресурсов в первую очередь.

Socket.Shutdown() должна вызывать только одна сторона, чаще всего - да, сервер. Вызывать с двух сторон - можно запутать протокол; не вызывать совсем - можно потерять данные, так как именно Shutdown проверяет, что всё успешно ушло.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]mavcan@lj
2012-10-18 12:11 (ссылка)
Я тут имел ввиду Shutdown, который SD_BOTH. Если односторонний - то можно и с друх сторон его делать. Просто на односторонний (SD_SEND) у меня аллергия, так как в где-то у меня (в обёртке .NET, в Windows CE, ...) есть глюк, из-за которого это всё не хочет работать правильно.
И, как всегда, предлагаю мой любимый вариант: растащить клиента и сервер на разные хосты и достать Wireshark :)

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]yigal_s@lj
2012-10-18 12:52 (ссылка)
да не поможет мне wireshark, ну увижу я что RST посылается, а толку?

Shutdown SD_BOTH можно и с двух сторон делать, у меня это на линуксе без проблем работает. Да и вообще ф-я Shutdown предназначается(?) для одностороннего закрытия коннекции, если коннекция закрывается на обе стороны, то она и не нужна в принципе, достаточно просто close вызвать. Что я и делаю и... валюсь под виндами.

Вот этот документ http://cs.baylor.edu/~donahoo/practical/CSockets/TCPRST.pdf ИДЕАЛЬНО описывает проблему, с которой я столкнулся. Неясно лишь как этот документ соотносится со стандартом ТСР и почему тем не менее на линуксе всё работает.

(Ответить) (Уровень выше)