Как я могу пинговать клиентов mysql?

#c# #php #mysql #.net

Вопрос:

Как я могу создать сценарий на стороне сервера для проверки клиентов на mysql и Windows form, чтобы узнать, вошли ли они в систему? Например, пропингуйте клиента, и он должен что-то сделать в ответ, чтобы убедиться, что он все еще в Сети.

Комментарии:

1. Соединения Mysql являются постоянными, поэтому, если клиент перейдет в автономный режим, он прекратит соединение. Вы также можете установить тайм-ауты для бездействующих подключений.

2. Извините, что я должен был уточнить больше. Поэтому на экране входа в систему моего приложения Windows я вхожу в пользовательскую таблицу в базе данных mysql и просто записываю ее с помощью записи под названием «islogged», и когда приложение завершает работу, я обновляю эту таблицу islogged = «НЕТ». Однако, если пользователь, например, теряет подключение к Интернету перед выходом из приложения, эта запись повторяется в islogged = «НЕТ», а затем они не могут снова войти в систему на более позднем этапе, потому что я проверяю, вошел ли пользователь в систему, прежде чем разрешить им войти

3. Если у вас есть двухуровневое приложение (клиент-база данных), то вы мало что можете с этим поделать, не переписывая существенно своих клиентов. Если у вас есть трехуровневое приложение (клиент-сервер приложений — база данных), вы можете включить эту функцию на уровне сервера приложений.

Ответ №1:

Вы не можете напрямую пинговать клиента с сервера, но есть несколько вариантов.

О тайм-аутах

Я думаю, что в любом случае вам нужно использовать тайм-аут на стороне сервера (wait_timeout), этот тайм-аут может быть установлен на уровне сервера или при подключении с клиента, например:

 SET SESSION wait_timeout = 60
 

Это необходимо, потому что клиент может внезапно исчезнуть, даже не закрыв tcp-соединение, и явный тайм-аут поможет mysql закрыть соединение и освободить ресурсы после нескольких секунд ожидания бездействия клиента. Согласно руководству mysql, тайм-аут по умолчанию довольно велик: 28800 секунд.

Есть один недостаток. Если во время нормальной работы ваш клиент может быть неактивен более секунды wait_timeout, то либо клиент должен знать, как работать с закрытым соединением (повторно подключиться, когда база данных сообщит, что оно отключено), либо он должен отправлять запросы «ping» (например select 1 ) по крайней мере каждые wait_timeout - 1 секунды.

Использование функции get_lock()

Начиная с mysql 5.7(а также в mariadb с 10.0.2) вы можете использовать несколько блокировок на уровне пользователя.

Блокировка, полученная с помощью GET_LOCK (), освобождается явно путем выполнения RELEASE_LOCK() или неявно при завершении сеанса (обычно или ненормально). Блокировки, полученные с помощью GET_LOCK (), не снимаются при фиксации или откате транзакций.

Таким образом, идея состоит в том, чтобы выполнить запрос get_lock при подключении клиента, например:

 SELECT GET_LOCK('logged_in_{CLIENT_ID}', timeout)
 

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

Эта блокировка будет автоматически снята сервером при отключении клиента или после отключения ожидания бездействия. Если блокировка свободна, get_lock() вернется 1 в противном случае (после секунд ожидания) вернется 0

Использование идентификатора процесса

Если вы не хотите использовать блокировки, можно использовать PID процесса.

Когда клиент подключается, вместо записи islogged = 'YES' вы можете использовать в качестве значения текущий идентификатор подключения (). Перед входом в систему вы можете проверить, что для текущего клиента нет активного процесса, подобного этому

 SELECT islogged FROM logged
INNER JOIN information_schema.processlist ON
    processlist.id = logged.islogged
WHERE
   client_id = ...
 

И если приведенный выше запрос ничего не возвращает, вы можете вставить новый pid в зарегистрированную таблицу

 REPLACE INTO logged SET islogged = CONNECTION_ID(), client_id = ...
 

Я бы предпочел использовать get_lock (), потому что он кажется проще, не страдает проблемами параллелизма и позволяет реализовать ожидание.

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