Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Радио-Сервер


Автор: MuForum 15.11.2011, 01:27
Доброго времени суток.
Интересуют любые данные/статьи/книги по так называемой схеме "радио-сервер".


# Задача: Реализовать радио-сервер.
1. Клиент подключается к серверу авторизации.
- Если всё прошло удачно, то сервер авторизации отправляет спец.пакет основному серверу.
2. Основной сервер пытается подключиться к клиенту.

1. Client -> AuthServer.
2. AuthServer -> GeneralServer.
3. GeneralServer -> Client.


P.S. -> Собственно проблемы вроде нет, кроме 3-его пункта.
- А именно, как подключиться к клиенту, если он сидит за натом?

Автор: boostcoder 15.11.2011, 01:34
Цитата(MuForum @  15.11.2011,  01:27 Найти цитируемый пост)
как подключиться к клиенту, если он сидит за натом?

пусть клиент сам подключается.

Автор: drug007 15.11.2011, 08:59
Цитата(MuForum @ 15.11.2011,  01:27)
Доброго времени суток.
Интересуют любые данные/статьи/книги по так называемой схеме "радио-сервер".


# Задача: Реализовать радио-сервер.
1. Клиент подключается к серверу авторизации.
- Если всё прошло удачно, то сервер авторизации отправляет спец.пакет основному серверу.
2. Основной сервер пытается подключиться к клиенту.

1. Client -> AuthServer.
2. AuthServer -> GeneralServer.
3. GeneralServer -> Client.


P.S. -> Собственно проблемы вроде нет, кроме 3-его пункта.
- А именно, как подключиться к клиенту, если он сидит за натом?


Вариант - GeneralServer это на самом деле сетевой клиент, а Client - это сетевой сервер и сетевой клиент в одном лице. В этом случае ваш Client первоначально через вызов функции connect() соединяется с AuthServer (где, естественно, вызвана функция listen()), передает ему свои данные, AuthServer передает данные GeneralServer (GeneralServer устанавливает соединение с AuthServer сразу после запуска также через connect()), после чего GeneralServer соединяется с Client с помощью вызова connect() с использованием данных, полученных от AuthServer, при этом, как уже говорил, на Client должна быть вызвана функция listen(). Т.о. Client должен будет вызывать listen() для соединения с GeneralServer и connect() для соединения с AuthServer.
Собственно, это чуть более развернутый вариант ответа Boostcoder.

Другой вариант - Client получает на AuthServer в случае успешной авторизации какой-то уникальный код, который одновременно с ним тоже от AuthServer получает GeneralServer. И когда Client соединяется с GeneralServer он передает ему данный код и GeneralServer сверяет его с полученным от AuthServer.  Тогда AuthServer и GeneralServer обычно ждут в вызове listen(), а Client использует только connect().
Но этот вариант близок к варианту когда авторизация полностью осуществляется на GeneralServer и оправдана в специфических ситуациях, на мой взгляд.

В случае клиента за NAT, нужно будет пробрасывать порт от роутера к клиентской машине, чтобы к нему мог подключится GeneralServer, к AuthServer подключится можно будет и без форвардинга. Т.е. такой вариант усложнит администрирование сети, но процедура простая и для приложений абсолютно прозрачная. 

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

Автор: MuForum 15.11.2011, 11:39
Как технически реализовать это я знаю и могу без проблем.
Остаётся только вопрос как будет GeneralServer подключаться к Client если он за NAT'ом.
- Думал что может быть есть какие-то хитрые манипуляции/секреты и т.д.

# Пошаговые действия:
## Идеальный вариант:
1. Client.exe (connect) -> (listen->accept) AuthServer.exe
2. AuthServer (UDP: IP/Port от клиента) -> (UDP:recvfrom) GameServer.exe
3. GameServer.exe (connect) -> (listen->accept) Client.exe


## В данном случае мой вариант, так как исходников одной программы у меня нет.
1. Launcher.exe (connect) -> (listen->accept) AuthServ.exe (Авторизация)
- Проверка авторизации.
2. AuthServer.exe (UDP) -> (UDP:recvfrom) GameServer.exe
- Отправляет IP и порт от клиента;
3. Game.exe (connect) -> (listen->accept) Launcher.exe
- Так как нет исходников игры, то делаем Launcher.exe как локальную проксю.
4. GameServer.exe (connect) -> (listen->accept) Launcher.exe
- Игровой сервер подключается к Launcher.exe

Собственно всё просто в том случае, если клиент не сидит за натом.
Мне интересно как это реализовано в программе TeamViewer, ведь там происходит пробивание ната.
- Разобрался: TeamViewer.exe постоянно опрашивает их сервер, а другой клиент подключается тоже к их серверу.
- То есть, получается что их сервер играет роль ProxyServer. (Client (connect) -> (recv/send) ProxyServer (recv/send) <- (connect) Client)


Причина моего изврата: Это как всегда многочисленные атаки на сервер.
Я реализовал систему фильтрации через WSAAccept() + CondificFunc(CF_REJECT), всё отлично работает, НО, если на протяжении нескольких минут продолжаются подключения, то затем все свободные сокеты торчат в системе в режиме ожидания, и из-за этого никто не может подключиться.
Однако кто уже подключился, никаких проблем не испытывает.
Изменение в системе значений реестра ветки [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Services\Tcpip\Parameters] мало что даёт.
Даже если уменьшим значений ключей: [TcpTimedWaitDelay:30]; [KeepAliveTime:60000]; [TcpMaxHalfOpen:500]; [TcpMaxHalfOpenRetried:400]; [TcpMaxPortsExhausted:5]; [synAttackProtect:1];



P.S. -> По моему мнению просто, с технической стороны было бы на много лучше если бы на прямую к GeneralServer никто не мог подключаться, а он бы сам подключался. А AuthServer уже если бы атаковали, то можно было и перезапускать его и т.д.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)