Архитектура системы обмена сообщениями
Есть клиент/сервер - имитация службы обмена сообщениями аля ICQ. Клиент умеет подсоединяться к серверу (при этом для каждого клиента на сервере создаётся трэд), отсылать ему команды и получать ответы на эти команды. Однако, требуется, что бы сервер мог и по своей собственной инициативе отправлять клиенту сообщения.
Вот тут вот и возникает проблема: как сделать так, что бы клиент мог параллельно:
1. отправлять команды / принимать ответы на них
2. получать сообщения от сервера
Если постоянно ожидать сообщения от сервера, приём ответов на команды станет невозможным, т.к. получим два процесса, читающих из одного конца сокета.
Есть тривиальное решение - сделать получение сообщений от сервера ещё одной командой клиента, а на сервере складывать сообщения в коллекцию или БД. Но будет ли это тру? smile
Кто-нибудь может подсказать, как поступить в данной ситуации?
Почему же? Тут в принципе два варианта: либо спрашивать время от времени сервер, нет ли новых сообщений (что по-моему как раз и не есть тру), либо открыть порт на прослушивание и не париться... По-моему это самое простое решение...
как сказать. я бы брал и смело юзал RPC. реализация просто и в тоже время эффективна.
http://ru.wikipedia.org/wiki/Remote_Procedure_Call
А на счёт второго сокета... судя по всему это действительно единственный вариант, при котором не придётся изобретать костыли...
Однако, тут тоже есть один скользкий момент. При каждом подключении придётся определять тип сокета - сокет для команд или сокет для сообщений.
С учётом моей предметной области это будет примерно так, как изображено на приатаченных диаграммах (uml там естественно не валидный - рисовал что бы отобразить суть идеи) :)
1. Запрос_комманды/получение_ответа суть операция атомарная. Поэтому классическая схема прокси, принимающей сообщение от сервера и передающей их тому или инному процессу, не применима, т.к. в этом случае придётся разделить процесс отправки запроса и получения результата (что неприемлимо).
Есть вариант организовывать надстройку над сокетом, инкапсулирующую в себе логику разделения данных, и обращаться к ней из обоих процессов как к обычному сокету. Однако, тут придётся организовывать буфер, т.к. возможна ситуация, когда информация придёт для одного процесса, а к надстройке обратиться другой. Надстройке придётся считать данные и положить их в буфер, пока к ней не обратиться нужный процесс. Вобщем имеем потенциальный источник ошибок.
2. На стороне сервера так же придётся контролировать одновременный доступ к сокету только одного процесса, т.к. возможен вариант, когда клиент запросит список пользователей, а другой отправит ему сообщение, ибо на сколько я помню матчасть - при записи одним процессом сокет не блокируется на запись другими
Концепция следующая.
С каждой стороны (код в принципе один и тот же) сокет обслуживают два потока управления: для записи и для чтения данных. Команды могут посылаться как с одной так и с другой стороны.
Отправка команды сводится к формированию объекта, представляющего команду и обработчику результата выполнения. Этот обработчик будет вызваться при получении отчета о выполнении команды на принимающей стороне, эти обработчики могут выполняться как в отдельном потоке управления, так и в потоке чтения из сокета. Все команды последовательно нумеруются, ответы принимающей стороны в своем заголовке содержат соответствующий номер команды, таким образом команда и обработчик ответа у нас связаны.
Процедура выполнения команды на принимающей стороне может происходить в отдельном потоке управления с очередью принятых команд. После выполнения команды отправляем отчет с результатами назад. В случае серверной части этот поток может быть один на несколько клиентов (зависит от сложности выполнения команд).