Произвольная двусторонняя связь через сокет UNIX - PullRequest
4 голосов
/ 23 декабря 2011

Я работал над сложной системой сервер-клиент в C, и я не уверен, как реализовать связь через сокет.

В двух словах, система представляет собой серверное приложение, которое взаимодействует сбазы данных и использует сокет UNIX для связи с одним или несколькими дочерними процессами, созданными с помощью fork().Целью детей является запуск игровых серверов.Процесс запуска игрового сервера выглядит следующим образом:

  1. Сервер / «менеджер» определяет игровой сервер в базе данных, которую необходимо создать.(Предположим, связь с базой данных уже отсортирована.)
  2. Менеджер разветвляет дочерний элемент («игровой контроллер»).
  3. Игровой контроллер устанавливает две пары каналов, затем разветвляется, заменяя стандартный дочерний элемент.с каналом, и это stdout и stderr с другим каналом.
  4. Затем дочерний элемент игрового контроллера запускает execlp(), чтобы запустить текущий исполняемый файл игрового сервера.

Мой опыт работы с сокетамидовольно минимально.Ранее я использовал select() в серверном приложении для «мультиплексирования» многочисленных клиентов, что демонстрирует простой пример, приведенный в документации GNU C здесь .

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

Итак, мне нужна своего рода «контекстная» система, где сокеты имеют смысл только между собой.Другими словами, когда команда отправляется от менеджера к игровому контроллеру, каждая сторона должна знать, кто спрашивает, и знать, что является ответом (и, следовательно, на какую команду это ответ).

Поскольку select() полезен только для того, чтобы знать, когда у нас есть входящие данные, и поток должен блокировать их, нужен ли мне другой поток, который отправляет данные и получает ответы?Для этого потребуется, чтобы каждый игровой контроллер, хотя технически был «клиентом», использовал гнездо для прослушивания и также использовал select()?

Надеюсь, я кратко объяснил систему и проблему;Я добавлю больше деталей, если требуется.Спасибо!

1 Ответ

1 голос
/ 23 декабря 2011

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

  1. Способ, которым сервер будет знать, каким клиентам соответствует какой сокет, заключается в том, что клиенты сообщат серверу. По сути, вам нужно иметь протокол входа в систему. Когда игровой контроллер подключается к серверу, он отправляет сообщение «Привет, я регистрируюсь как контроллер foo1 на хосте xyz, порт abc ...» и все, что сервер должен знать о своих клиентах. Сервер будет хранить структуру данных, которая сопоставляет сокеты с метаданными клиента, состоянием и т. Д. Каждый раз, когда он получает новое сообщение, он может легко сопоставить входящий хост / порт с его метаданными. Или ваш протокол может требовать, чтобы при каждом входящем сообщении клиент отправлял имя, зарегистрированное в качестве поля.

  2. Обработка запроса / ответа может быть выполнена несколькими способами. Сначала давайте разберемся с сетевой частью на стороне сервера. Как вы упомянули, одним из способов управления этим является использование select (или poll, или epoll) для мультиплексирования сокетов. На самом деле это обычно считается более сложным способом ведения дел. Другой способ - создать поток (или обработать процесс, который в наши дни встречается реже) для каждого входящего клиента. Каждый порожденный поток может читать свой назначенный сокет, отвечая на сообщения по одному, не беспокоясь о том, что есть другие клиенты, помимо собственного, с которым он имеет дело. Эта простая модель «один в один поток к сокету» ломается, если есть много клиентов, но если это не так, то это стоит рассмотреть.

Часть 2 действительно касается только клиента, отправляющего серверу сообщение, и ответа сервера. Что происходит, когда сервер хочет инициировать связь? Как это происходит и как клиент справляется с этим? Кроме того, как вы смоделируете модель коммуникации на уровне приложения, то есть, предположив, что у нас есть часть чтения / записи, как мы узнаем, что отправить? Возможно, вы захотите смоделировать вещи с точки зрения конечных автоматов. Есть еще много чего, например, что происходит, когда клиент падает. Как насчет того, когда сервер падает? Кроме того, что, если у вас действительно есть желание использовать select, возможно, потому что вы ожидаете много клиентов? Я постараюсь добавить больше к этому ответу завтра.

...