Разработка серверного и клиентского приложений на С++, реализующих взаимодействие на основе механизма передачи сообщений (с использованием стандартных классов CSocket/CAsyncSocket). Взаимодействие между клиентами и сервером может быть реализовано как в режиме автоматических извещений (потребует постоянного соединения каждого клиента с сервером, а также реализацию локальной очереди сообщений на стороне клиента), так и в режиме регулярного опроса клиентами сервера. Основные типы запросов: - запрос регистрации клиента (получение уникального идентификатора от сервера); - отправка сообщения; - запрос сообщения (для режима опроса); - завершение сессии (удаление клиента из списка). Сообщение состоит из заголовка и данных. Заголовок включает поля: - отправитель; - получатель (идентификатор другого клиента, идентификатор сервера, псевдоидентификатор "все клиенты" для широковещательных сообщений); - тип сообщения; - размер сообщения. При создании объектов-сообщений целесообразно использовать умные указатели. С каждым клиентом сопоставляется объект класса (например, MClient или Session), включающий следующие поля и функции: - идентификатор клиента; - очередь сообщений, адресованных клиенту; - критическая секция либо мьютекс для защиты очереди от одновременного использования; - событие (event) с автоматическим сбросом (для режима с автоматическим извещением); - клиентский сокет (для режима с автоматическим извещением); - время последнего взаимодействия с клиентом; - функцию добавления сообщения в очередь; - функцию проверки наличия сообщений в очереди; - функцию получения (и последующего удаления) сообщения из очереди; - функцию, определяющую превышение клиентом допустимого периода неактивности. Работа с очередью защищается критической секцией либо мьютексом. Сервер хранит контейнер (map либо vector) объектов MClient/Session, соответствующих активным клиентам. Взаимодействие клиентов с сервером включает три основные стадии: 1. Первичная регистрация: - клиент отправляет на сервер запрос на регистрацию; - сервер формирует новый идентификатор клиента (на основе глобального счетчика), создает объект класса MClient, добавляет его в список активных клиентов, отвечает клиенту, передав в ответе его идентификатор. 2. Основная работа: - клиент формирует сообщение, отправляя его на сервер (фунция отправки должна автоматически подставить идентификатор отправителя в соответствующее поле заголовка); - сервер, получив сообщение, проверяет корректность его отправителя и адресата (присутствуют ли они в контейнере активных клиентов), далее добавляет его в очередь клиента-адресата либо в очереди всех клиентов в случае широковещательного сообщения; в случае режима с автоматическим извещением устанавливает события, связанные с получателями; - в случае реализации режима с автоматическим извещением передача очередного сообщения клиенту инициируется сервером (в отдельном потоке, содержащем цикл, который получает события от принимающего потока и проверяет, есть ли сообщения в очереди); в этом случае на стороне клиента потребуется дополнительная реализация локальной очереди сообщений; - в случае реализации режима с опросом после получения идентификатора клиент запускает отдельный поток, который с заданной периодичностью обращается к серверу, запрашивая наличие ожидающих его сообщений; получив запрос, сервер проверяет наличие клиента в контейнере активных клиентов, наличие сообщений и либо считывает очередное сообщение, направляя его клиенту, либо сообщает об отсутствии сообщений; обработка каждого клиентского запроса осуществляется в отдельном потоке. - дальнейшая обработка сообщения клиентом в обоих случаях зависит от типа сообщения и может быть реализована либо с помощью блока switch, либо с помощью контейнера с указателями на функции-обработчики; - любое взаимодействие с клиентом приводит к корректировке поля, в котором хранится время последнего взаимодействия. 3. Завершение работы: - по явному запросу клиента соответствующий ему объект удаляется из списка активных клиентов; - по таймауту: сервер содержит отдельный поток, периодически проходящий по списку клиентов и удаляющий тех, интервал взаимодействие с которыми превысил таймаут. В качестве демонстрации работоспособности клиентам достаточно реализовать получение с консоли текстовой строки, ее широковещательной отправки (например, с типом сообщения MT_TEXT) и вывода в консоль полученной строки. С точки зрения развития: крайне желательно унести большую часть кода SocketServer.cpp в отдельный класс Server, а Message Message::send и static int clientID в отдельный класс Client.