LINUX.ORG.RU

Теперь про сокеты

 , , ,


0

2

Собсно:

Получаю дескриптор сокета (socket(AF_INET...), биндю его, листю его. Подключаюсь телнетом, отправляю текст, сервер его получает, все чики-пуки.

Но, после того как вырубаю сервер через Ctrl+C, при повторном его запуске он фейлится на бинде. А через несколько запусков «отходит». В данный момент запилил с goto retry_connect; с sleep(3); но этж кастыль еще какой.

Да, я уже загуглил. Есть SO_REUSEADDR но про него говорят нехорошее вот тут.

У меня таки вопрос - а как эту «проблему» решали вы?

SO_LINGER -> { 0, 0 }

только post-factum тебе верно сказал. Да и за REUSEADDR ты почитай внимательнее, когда его рекомендуется, а когда нет.

anonymous
()
Ответ на: комментарий от deep-purple

А вообще, серверный код пиши так, как будто все клиенты специально коннектятся к тебе, чтобы чего-то наворотить, а демону система может прислать рандомный сигнал в любой момент. Обычно для этого достаточно правильно ловить EPOLLRDHUP/EPOLLHUP и позиксовые сигналы через epoll_pwait().

post-factum ★★★★★
()
Последнее исправление: post-factum (всего исправлений: 1)
Ответ на: комментарий от post-factum

коннектятся к тебе, чтобы чего-то наворотить

Ну, потому и сижу, разбираюсь.

а демону система может прислать рандомный сигнал

А про сигналы у меня тут отдельный топик есь )) мож чего тоже посоветуешь?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deterok

А как же ) Пишут. Ожидая, что клиент всегда будет присылать правильные запросы, не более определённой длины

Harald ★★★★★
()
Ответ на: комментарий от Harald

Где это видано?
Я даже и представить не могу себе, что можно быть таким наивным.

deterok ★★★★★
()

В голове есть 5 варианта

1. закрытие соединения ВСЕГДА инициалезирует клиент - что в реальном мире попросту не возможно (зато у тебя не будет TIME_WAIT сокетов).
2. При старте биндить на другой не занятый порт - что не всегда возможно и в 99% глупо.
3. Перевести TCP/IP стек в его исконное состояние (когда конекшен акцептился на порт отличный от листен порта) - как это сделать я хз, разве что в музее найти древний сервер с древней ОС :D, и то не факт что новые операционки / роутеры / фаерволы - с таким мамонтом нормально заработают.
4. Сделать TIME_WAIT меньше чем время перезапуска процесса - глупая затея, да и там лимиты есть (помоему в 60 секунд) и чтоб его обойти нужно будет ядро патчить.
5. Использовать SO_REUSEADDR - что я всегда и делаю (с ним могут быть проблемы только если ты делаеш SO_REUSEADDR + bind + connect, но если делать SO_REUSEADDR + bind + listen + accept - то все ок).

zaz ★★★★
()
Последнее исправление: zaz (всего исправлений: 2)
Ответ на: комментарий от zaz

Тут еще подродностей надо накинуть. Это вообще типа будет remote-access. Оно в отдельном потоке крутится. Все команды запихнуты в структуру, т.е. размер известен. Ответы, да, могут быть разные, может там инфы запросили (много данных), а может только и надо срыгнуть статус: команда (не)выполнена.

Вобщем сделал как. Читаю только одного клиента, всегда одного, остальные в очередь. Повесил таймаут 10 сек, если клиент не успел отдать-принять - послал лесом и закрыл сокет.

Но! Если какой-то злец решит набросать мне очередь ожидающих, этж получится кака. Или не?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от anonymous

SO_LINGER -> { 0, 0 }

Эта хрень через раз работает. Но оставил её всеравно. Так же и goto свое оставил на бинде. И точно надо будет sighandler+close как подсказал post-factum. А первые два костылика всеравно пригодятся если его кильнули не дав опомниться.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Идея с таймаутами выглядит очень неочень, вобще если гдето чтото начинают синхронизировать через слипы/таймауты то меня немного коробит :). Например почему 10 секунд а ну 11 или 8 ? А что при времени больше/меньше чем 10 секунд будет хуже работать? ну и тд. (конечно есть куча мест где таймауты нужны, но когда они влияют на скорость отклика всей системы то это уже не хорошо).

С таким подходом система не стабильна по архитектуре, во первых получить 10 секундный таймаут ты можеш на ровном месте даже в локальной сети (если потеряется 1-2 пакета гденебудь в проводах или свиче, или ктото приконектится к тебе и потеряет сеть/питание) + вот то число которое ты передаеш в listen это и есть максимальный размер очереди, если она переполнится то будет конекшен рефьюзед на все новые соединения. Можно конечно сделать очередь большой - например 1000, но что будет если к тебе зайдут 1000 кривых клиентов (которые ничего не будут слать а только конектится) - у тебя система тубо вырубится на 3 часа (10000 секунд).

Сдесь есть 2 вариант - 1 плодить на каждого клиента отдельный поток и его там обслуживать (что дорого по ресурсам и можно просто убить сервер кучей потоков), 2 - Обслуживать всех в одном потоке используя не блокирующий ввод/вывод + select/poll/epoll (я бы посоветовал взять poll - для малого ко-ва сокетов он сравним с epoll по производительности и у него очень простой API и нету граблей как в селекте).

zaz ★★★★
()

Я жду когда сокет освободится, потом занимаю его.

pathfinder ★★★★
()
Ответ на: комментарий от zaz

А почему именно полл а не селект? Я просто читаю щас про селект, так то ничего особо сложного нет, полл-еполл тоже почитаю. Но вот нюансы-отличия, где какой лучше использовать и почему. Вот это интересует.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

А почему именно полл а не селект?

Потому что угребищный интерфейс.

полл-еполл тоже почитаю

poll и epoll - довольно разные вещи.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Потому что угребищный интерфейс

Вычитал, что раньше полл был оберткой над селект, теперь это давно уже нечто самостоятельное. До еполла еще не добрался.

довольно разные вещи

А можно пару абзацев концентрированной инфы?

deep-purple ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.