Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 Аватар для dailydose
671 / 217 / 88
Регистрация: 21.07.2016
Сообщений: 1,036
Записей в блоге: 2

Как реализовать роутинг для WebSocketServer?

04.01.2018, 12:07. Показов 788. Ответов 0
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Клиенты могут отправлять серверу разные сообщения в формате JSON:
JavaScript
1
2
3
4
5
6
{
    Type: "AUTH_MESSAGE",
    Payload: {
        UserName: "dailydose"
    }
}
JavaScript
1
2
3
4
5
6
{
    Type: "CHAT_MESSAGE",
    Payload: {
        Message: "hello world"
    }
}
Сервер же должен их принимать и обрабатывать их в зависимости от типа сообщения
C#
1
server.OnMessage = webSocketMessage => Router.Handle(socket, webSocketMessage, this);
Я попробовал реализовать этот функционал на основе Цепочки обязанностей(Chain of responsibility).

Router:
Router
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    public static class Router
    {
        static Router()
        {
            Handlers = new List<BaseHandler>()
                           {
                               new ChatHandler(),
                               // new UsersListHandler(),
                               new AuthHandler(),
                               new InvalidHandler()
                           };
        }
 
        private static List<BaseHandler> Handlers { get; }
 
        public static void Handle(IWebSocketConnection socket, string webSocketMessage, IServer server)
        {
            var messageType = Newtonsoft.Json.JsonConvert
                .DeserializeObject<WebSocketMessage<Payloads.ChatMessage>>(webSocketMessage).Type;
 
            foreach (var handler in Handlers)
            {
                if (handler.CanHandle(socket, messageType, server))
                {
                    handler.Handle(socket, webSocketMessage, server);
                    return;
                }
            }
        }
    }


handlers:
handlers
C#
1
2
3
4
5
6
7
8
9
10
11
    public abstract class BaseHandler
    {
        protected abstract string Target { get; }
 
        public abstract void Handle(IWebSocketConnection socket, string webSocketMessage, IServer server);
 
        public virtual bool CanHandle(IWebSocketConnection socket, string messageType, IServer server)
        {
            return messageType == Target;
        }
    }
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    public class AuthHandler : BaseHandler
    {
        protected override string Target => AuthMessage.Type;
 
        public override bool CanHandle(IWebSocketConnection socket, string messageType, IServer server)
        {
            return base.CanHandle(socket, messageType, server) && !server.ConnectedSockets.ContainsKey(socket);
        }
 
        public override void Handle(IWebSocketConnection socket, string webSocketMessage, IServer server)
        {
            Authorize(socket, webSocketMessage, server);
        }
 
        private void Authorize(IWebSocketConnection socket, string webSocketMessage, IServer server)
        {
            try
            {
                var data = 
                    Newtonsoft.Json.JsonConvert.DeserializeObject<WebSocketMessage<AuthMessage>>(webSocketMessage);
                if (server.ConnectedSockets.ContainsValue(data.Payload.UserName))
                {
                    DisconnectSocket(socket, data, server);
                }
                else
                {
                    ConnectSocket(socket, data, server);
                }
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine(e.ToString());
            }
        }
    }
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    public class ChatHandler : BaseHandler
    {
        protected override string Target => ChatMessage.Type;
 
        public override void Handle(IWebSocketConnection socket, string webSocketMessage, IServer server)
        {
            try
            {
                var data =
                    Newtonsoft.Json.JsonConvert.DeserializeObject<WebSocketMessage<ChatMessage>>(webSocketMessage);
                var chatMessage = new ChatMessage()
                {
                    UserName = server.ConnectedSockets[socket],
                    Message = data.Payload.Message
                };
                SendToAll(chatMessage, server);
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine(e.ToString());
            }
        }
 
        public void SendToAll(ChatMessage chatMessage, IServer server)
        {
            var message = Helper.BuildMessage(chatMessage);
            foreach (var client in server.ConnectedSockets)
            {
                client.Key.Send(message);
            }
        }
    }
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    public class InvalidHandler : BaseHandler
    {
        protected override string Target => string.Empty;
 
        public override bool CanHandle(IWebSocketConnection socket, string messageType, IServer server)
        {
            return true;
        }
 
        public override void Handle(IWebSocketConnection socket, string webSocketMessage, IServer server)
        {
            var invalidMessage = new Payloads.InvalidMessage()
            {
                Message = "Обнаружена ошибка. Предоставьте, пожалуйста, эту информацию разработчикам: "
                    + webSocketMessage
            };
            socket.Send(Helper.BuildMessage(invalidMessage));
        }
    }


messages:
messages
C#
1
2
3
4
5
    public class WebSocketMessage<T> where T : Payloads.BaseMessage
    {
        public string Type { get; set; }
        public T Payload { get; set; }
    }
C#
1
2
3
4
5
    public class BaseMessage
    {
        protected virtual string MessageType { get; } = string.Empty;
        public override string ToString() => MessageType;
    }
C#
1
2
3
4
5
6
7
8
    public partial class AuthMessage : BaseMessage
    {
        public const string Type = "AUTH_MESSAGE";
        public string Message { get; set; }
        public StatusCode Status { get; set; }
        public string UserName { get; set; }
        protected override string MessageType => Type;
    }
C#
1
2
3
4
5
6
7
8
    public class ChatMessage : BaseMessage
    {
        public const string Type = "CHAT_MESSAGE";
        public string Message { get; set; }
        public string Time { get; set; } = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        public string UserName { get; set; }
        protected override string MessageType => Type;
    }
C#
1
2
3
4
5
6
    public class InvalidMessage : BaseMessage
    {
        public const string Type = "INVALID_MESSAGE";
        public string Message { get; set; }
        protected override string MessageType => Type;
    }


И как-то мне оно не очень нравится:
Router - статический класс и содержит в себе экземпляры обработчиков.
Везде во все обработчики передаются аргументы (IWebSocketConnection socket, string webSocketMessage, IServer server) даже там где они не нужны.

Подскажите, пожалуйста, более правильный подход реализации роутинга и/или предложите модификации этого кода.

Спасибо!
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
04.01.2018, 12:07
Ответы с готовыми решениями:

Роутинг для Get параметров
Приветствую. Есть такой роутинг $start = explode('?', $_SERVER); $start = array_shift($start); if ( $start == '/' ) { $page...

[Web Api] Как настраивается роутинг?
Вопрос в том &quot;в какой последовательности сопоставляются роуты и экшины&quot;? (ветвет хотелось бы слышать в 2х вариантах: как решить мой...

Роутинг - как сделать так, чтобы работала внешка и локалка
В общем такая проблема. В компании есть закрытая сеть и открытая(обыкновенный вай фай роутер с белым Ип адресом), закрытая соотвественно...

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
04.01.2018, 12:07
Помогаю со студенческими работами здесь

Реализовать класс для матриц. В этом классе реализовать интерфейс, содержащий методы для выполнения операций
Реализовать класс для матриц. В этом классе реализовать интерфейс, содержащий методы для выполнения следующих операций: - сложение -...

Как настроить Angular routes в комбинации с Zend Framework 2 (при условии, что ZF2 роутинг отключён) и Smarty (.tpl-ки)
Доброго времени суток, форумчане! Я использую Zend Framework 2, Smarty (шаблонизатор), AngularJS v1.6.4 и у меня следующая структура...

незнаю как вывести полное решение для задачки.смысл улавливаю, а как реализовать - туплю
Задана окружность, с помощью координат центра и радиуса. Определить, лежит ли она полностью в первой четверти. 1вывожу окружность и ...

Как реализовать выбор строк таблицы посредством CheckBox для дальнейшей работы с этими строками? (как в phpMyAdmin)
Как реализовать выбор строк таблицы посредством CheckBox для дальнейшей работы с этими строками? (как в phpMyAdmin) Ковырялся в коде...

Как реализовать шрифт для раздела
Ребята озадачился задачей, как можно сделать чтоб разделы выводились таки вот шрифтом: Monotype Corsiva?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
1
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
Установка Emscripten SDK (emsdk) и CMake на Windows для сборки C и C++ приложений в WebAssembly (Wasm)
8Observer8 30.01.2026
Чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. Система контроля версиями Git. . .
Подключение Box2D v3 к SDL3 для Android: физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
Влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru