LINUX.ORG.RU

[TCP] Перезапуск сервера

 


0

1

Есть сервер игры, к которому клиенты подключаются по tcp, типичное время сессии около 30 минут. Возможно ли организовать перезапуск сервера таким образом, чтобы уже подключенные клиенты продолжали сидеть на старом, а вновь подключавшиеся оказывались на новой копии сервера? Когда все клиенты отключатся от старого сервера, он закрывается.

Пробовал закрывать слушающий сокет и запускать вторую копию, но она ругается на уже занятый порт. Запрос к гуглу, выдающий релевантную инормацию, не смог придумать. Как правильно организовать такой перезапуск?

★★★★★

закрывать слушающий сокет на первом сервера, и открывать на втором

anonymous
()
  • сохраняешь состояние;
  • уведомляешь клиент;
  • перезапускаешь сервер;
  • востонавливаешь соединение;
  • востонавливаешь состояние.
  • ...
  • profit!!!
nanoo_linux
()
Ответ на: комментарий от nanoo_linux

Фу. У нормальных платформ есть горячая замена кода

anonymous
()

в erlang/otp можно. Причем делается это левой пяткой.

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

> sshd почти всю жизнь так умеет.

sshd - это один серверный процесс на клиента, поэтому тривиально.

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

Пробовал, пишет что порт занят

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

Это нужно для обновления сервера до новой версии, возможно частично несовместимой со старой, так что сохранение состояния с восстановлением не выход.

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

возможно сделать такое: для каждой новой несовместимой версии сервера инкрементировать чесло-версию протокола в пакетах между коиентом и сервером. на вашей стороне тогда можно по полю версии балансировать траффик между разными серверам.

val-amart ★★★★★
()
Ответ на: комментарий от anonymous

> Ну я же тебе сказал как.

при попытке перезапущенного сервера слушать порт пишет, что он уже занят

unC0Rr ★★★★★
() автор топика

Делай как апач, ссш и многие другие сервисы - принимает соединение один процесс, а обслуживает другой (дескриптор можно передать через unix socket). В таком случае при перезапуске дочерний обработчик продолжит работать и обслуживать клиентов, а новых уже не получит, умрет он когда поймет что клиенты отвалилсь и парент отвалился.

Либо при перезапуске делать форк, перед ним закрывать порт на котором принимаются соединения, и выставлять какой-то флаг чтобы когда все клиенты отвалятся выходить..

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

А да, при втором варинте нужно для слушающего порта выставить SO_REUSEADDR это позволит срзу же открыть порт в другом процессе, иначе надо будет жадть пока кончится TIME_WAIT..

Мложет в этом и проблема?

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

Т.е не порта, а сокета, и только сейчас дочитал ;)) Дело походу именно в этой опции

man setsockopt

OxiD ★★★★
()

можно просто реализовать через iptables, но потребуются значительные права на перезапуск игрового сервера. Вкратце поясню: сервер игры садится на случайный порт и пишет его номер в файл, а скрипт перенаправляет новые tcp соединения с фиксированного (известного клиентам) порта на тот который прочтёт из файла.

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

частично несовместимой со старой

а клиент? если клиент не обновляется, состояние разве не остаётся таким же? сохраняй все в xml. а потом парси обратно.

Но этот вариант хорош, если состояние не сильно большое и сложное. Если это не так, то лучше через прокси, да. Хотя там тоже косяки могут быть. Все зависит от протокола. Если он «атомарный», тогда вариант с прокси самый выгодный. Если нет - то одной лишь проксей не отделаешься.

А чего там за игра хоть?

nanoo_linux
()
Ответ на: комментарий от OxiD

> апач, ссш и многие другие сервисы

обрабатывают клиента независимо от остальных клиентов, потому имеют возможность запустить по отдельному обработчику на каждого из них, мне этот вариант не подходит

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

> а клиент? если клиент не обновляется, состояние разве не остаётся таким же? сохраняй все в xml. а потом парси обратно.

клиент не обновляется, но могут подсоединиться обновлённые клиенты

Но этот вариант хорош, если состояние не сильно большое и сложное

в принципе, не сложно сохранить состояние. Дело в том, что внутренняя логика сервера может меняться, и загрузить состояние будет уже проблематично. Писать конвертер состояний для каждого обновления тоже неинтересно, т.к. кроме меня это никому не нужно, да и мне только один раз.

Если он «атомарный», тогда вариант с прокси самый выгодный

Что значит атомарный в данном контексте?

А чего там за игра хоть?

hedgewars

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

Что значит атомарный

Под этим я имел ввиду, что если представить сервер в качестве автомата конечных состояний, то в момент начала транзакции и в момент её окончания сервер находится в одном и том же состоянии. Например, если назначение сервера просто передавать от клиента к клиенту инфу о том, кто куда идёт/стреляет, и больше ничего, то это, можно сказать, атомарный. Короче, это не важно.

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

Тогда нет, состояние меняется на большей части запросов

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

> SO_REUSEADDR

уже использую, не помогает

Это странно, еслия правильно понимаю ты делаешь close(socket) и потом форкаешься?

Оно либо поможет либо ошибка в алгоритме. В какой момент вызываешь setsockopt? Надо сразу после socket, не после listen.

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

Форкаюсь после закрытия, да. Вот как открываю сокет:

    E.bracket
        (socket AF_INET Stream proto)
        sClose
        (\sock -> do
            setSocketOption sock ReuseAddr 1
            bindSocket sock (SockAddrInet (listenPort si) iNADDR_ANY)
            listen sock maxListenQueue
            startServer si sock
        )
unC0Rr ★★★★★
() автор топика
Ответ на: комментарий от unC0Rr

попробуй поставить слипов и погляди что происходит через strace -f -p <pid>

Сокет точно закрывается? после close() проверь это через netstat Не может ли вызов закрытия отложится до лучших времен в связи с ленью хаскеля?

на си это точно бы работало, т.к после закрытия сокета с опцией so_reuseaddr сокет сразу закрывается, без этой опции надо ждать TIME_WAIT

соответсвенно с помощью strace и netstat ты можешь понять что происходит.

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

Ну по крайней мере я сам многократно пробовал запускать с этой опцией утилиты, прибивать их ^C и перезапускать ;) Без этой опции все происходит как ты говоришь - порт занят, а с ней все шоколадно.

И кстати ты (интерпретатор хаскеля) точно вызываешь close __до__ форка? Потому что, если ты сделаешь это после, то сокет будет унаследован дочкой и соответственно не будет закрыт.

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

> точно вызываешь close __до__ форка?

Вроде да, в коде так и написано, впрочем проверю всё, как ты сказал. Спасибо за подсказки :)

unC0Rr ★★★★★
() автор топика

прочитав тему, «показалось», что ты стоишь на пути к написанию плагинов к серверу.

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

Да нет, мне всего лишь нужно иметь возможность обновить сервер, не прерывая идущих игр. Никому не понравится, если после 15-20-30 минут матча выключится сервак.

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

ну что, выяснил в чем дело? ну или что видно?

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