Объектно-ориентированная сеть - PullRequest
16 голосов
/ 08 февраля 2011

Я написал несколько сетевых систем и хорошо представляю, как работает сеть. Однако я всегда получаю функцию приема пакетов, которая является гигантским оператором переключения. Это начинает доходить до меня. Я бы предпочел хороший элегантный объектно-ориентированный способ обработки принимаемых пакетов, но каждый раз, когда я пытаюсь найти хорошее решение, я всегда заканчиваю неудачей.

Например, допустим, у вас есть сетевой сервер. Это просто ожидание ответов. Пакет приходит, и сервер должен проверить пакет, а затем он должен решить, как его обработать.

В данный момент я делаю это, включая идентификатор пакета в заголовке, а затем получаю огромное количество вызовов функций, которые обрабатывают каждый тип пакета. Со сложными сетевыми системами это приводит к монолитному переключению, и мне действительно не нравится обрабатывать его таким образом. Одним из способов, который я рассмотрел, является использование карты классов-обработчиков. Затем я могу передать пакет соответствующему классу и обработать поступающие данные. Проблема, с которой я столкнулся, заключается в том, что мне нужен какой-то способ «зарегистрировать» каждый обработчик пакетов на карте. Обычно это означает, что мне нужно создать статическую копию класса, а затем в конструкторе зарегистрировать ее в центральном обработчике пакетов. Несмотря на то, что это работает, это действительно кажется не элегантным и сложным способом справиться с этим.

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

Может кто-нибудь указать мне на лучший способ обработки входящих пакетов? Ссылки и полезная информация приветствуются!

Извиняюсь, если я не описал свою проблему хорошо, так как моя неспособность описать ее хорошо также является причиной, по которой мне так и не удалось найти решение.

Ответы [ 7 ]

5 голосов
/ 08 февраля 2011

О способе обработки типа пакета: для меня карта самая лучшая.Однако я бы использовал простой массив (или вектор) вместо карты.Время доступа будет постоянным, если вы перечислите типы пакетов последовательно от 0.

Что касается структуры класса.Есть библиотеки, которые уже выполняют эту работу: Доступные языки определения сетевого протокола игры и генерация кода .Например, Протокол Google Buffer кажется многообещающим.Он генерирует класс хранения с методами получения, установки, сериализации и десериализации для каждого сообщения в описании протокола.Язык описания протокола выглядит более или менее богатым.

1 голос
/ 25 апреля 2019

Я бы использовал Flatbuffers и / или Cap'n Proto генераторы кода.

1 голос
/ 10 февраля 2011

Еще одним способом решения этой задачи является создание конечного автомата с использованием шаблона состояний.

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

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

Если вы хотите повысить производительность, вы все равно можете использовать конечный автомат, но пропустите часть OO.

1 голос
/ 09 февраля 2011

Вы хотите продолжать использовать тот же протокол пакетной сети, но перевести его в объект при программировании, верно?

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

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

1 голос
/ 08 февраля 2011

Когда вы делаете ООП, вы пытаетесь представить каждую вещь как объект, верно?Так что ваши протокольные сообщения тоже становятся объектами;у вас, вероятно, будет базовый класс YourProtocolMessageBase, который будет инкапсулировать поведение любого сообщения и от которого вы унаследуете свои полиморфно-специализированные сообщения.Тогда вам просто нужен способ превратить каждое сообщение (то есть каждый YourProtocolMessageBase экземпляр) в строку байтов, и способ сделать обратное.Такие методы называются методы сериализации ;существует несколько реализаций на основе метапрограммирования.

Быстрый пример на Python:

from socket import *
sock = socket(AF_INET6, SOCK_STREAM)
sock.bind(("localhost", 1234))
rsock, addr = sock.accept()

Блоки сервера, запуск другого экземпляра для клиента:

from socket import *
clientsock = socket(AF_INET6, SOCK_STREAM)
clientsock.connect(("localhost", 1234))

Теперь используйте встроенный в Python модуль сериализации, pickle;клиент:

import pickle
obj = {1: "test", 2: 138, 3: ("foo", "bar")}
clientsock.send(pickle.dumps(obj))

сервер:

>>> import pickle
>>> r = pickle.loads(rsock.recv(1000))
>>> r
{1: 'test', 2: 138, 3: ('foo', 'bar')}

Итак, как вы можете видеть, я только что отправил через link-local объект Python * .Разве это не ООП?

Я думаю, что единственной возможной альтернативой сериализации является поддержание классов идентификаторов bimap ⇔.Это выглядит действительно неизбежно.

1 голос
/ 08 февраля 2011

По моему опыту, табличный анализ является наиболее эффективным методом.

Хотя std::map это хорошо, я в конечном итоге использую статические таблицы.std::map не может быть статически инициализирован как таблица констант.Он должен быть загружен во время выполнения.Таблицы (массивы структур) могут быть объявлены как данные и инициализированы во время компиляции.Я не встречал достаточно больших таблиц, где линейный поиск был узким местом.Обычно размер таблицы достаточно мал, поэтому накладные расходы в двоичном поиске медленнее, чем в линейном поиске.

Для высокой производительности я буду использовать данные сообщения в качестве индекса в таблице.

1 голос
/ 08 февраля 2011

Карта экземпляров обработчиков - это, по большей части, лучший способ справиться с этим.В этом нет ничего легкомысленного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...