2

Впервые я пытаюсь реализовать некоторый сетевой протокол через TCP/IP. Я разработал один, но я не уверен, насколько он эффективен.Каковы наилучшие методы проектирования и реализации сетевых протоколов?

Дизайн

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

Например, если клиент хочет отправить GET ASD, он фактически отправит 7 GET ASD (при условии, что пространство является разделителем).

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

Реализация

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

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

Я думаю, что есть два способа хранения запросов в буфере, пока они не служили:

  1. Всякий раз, когда сервер получает новый кусок символов, сервер добавит его к правой стороне буфера. Как только буфер будет содержать полный запрос, сервер будет обрабатывать его и перемещать влево весь остальной буфер в начале буферного пространства.

  2. Некоторые циклические буфера, которые не перемещают буфер в начале после запроса обработки.

Это мои мысли о реализации буферов с асинхронным I/O в виде (сервер будет использовать Epoll/Kqueue/выберите для получения запросов от клиентов). Я думаю, что если сервер не будет использовать асинхронный ввод-вывод для связи с клиентами, то реализация буфера будет намного проще.

Также я не решил, как сервер должен вести себя, когда он получает неверный запрос. Должна ли она закрывать связь с клиентом?

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

+0

Требования к API важны для анализа перед выполнением любого вида дизайна. Если вы можете подробно остановиться на них, это может быть проще. –

+0

Я был очень воодушевлен Редисом и для цели обучения Я начал небольшой проект Kivi (K/V Store): http://github.com/giolekva/kivi Итак, такие команды, как GET, SET, DEL, INCR, ... как в Redis. – giolekva

+0

(Комментируя, потому что у меня нет полного ответа на ваш вопрос): Я обнаружил, что лучше предотвратить возможность искаженных запросов. В этом случае длина и запрос могут быть непоследовательными, поэтому я бы покончил с длиной. Вместо этого у вас может быть какой-то специальный терминатор ('' \ 0'' хорошо работает во многих случаях).Конечно, по-прежнему существует вероятность того, что клиент отправит бесконечную строку для перегрузки сервера, но по крайней мере вы не будете висели, ожидая большего количества байтов, если длина была неправильной. – Jonathan

ответ

2

Вам нужен человекообразный протокол? Если нет, то я бы предложил двоичный код, начните с x байтов длины команды, а затем сформируйте остальную часть сообщения, как вы сочтете нужным; конечно, остальное сообщение может быть текстовым, если вы предпочитаете ...ИМХО это намного проще справляться с сервером, так как вам не нужно сканировать все входные байты, чтобы определить, когда сообщение закончится.

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

Для защиты от атак типа «отказ в обслуживании» у вас должен быть тайм-аут на ваших прочитанных данных. Нет полного сообщения в x, и вы отключите его.

Нарушение сообщения, вы отключите. У IMHO Postel есть что ответить; Протоколы IMHO лучше, когда вы педантичны, что люди получают вещи ВПРАВО и принимают не что иное ...

Размер сообщения больше, чем вы разрешите, отключите.

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

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

2

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

Посмотрите на XDR или BER (ASN.1) для двоичного кодирования данных. Есть библиотеки для тех, которые заботятся о endiannes и беспорядке выравнивания. Например, упаковка каждого пакета в непрозрачном пакете XDR позволяет более эффективно проектировать сервер (1 модуль интерфейса TCP, который отправляет необработанные непрозрачные поля в соответствующие обработчики, не зная, что означает каждый пакет).

Как упоминалось Len Holgate, обязательно укажите, что должно происходить в особых случаях (неправильные пакеты, отсутствие ответа) или должны быть какие-либо пакеты keep-alive? Если да, то как часто? Должны ли быть какие-то переговоры между клиентом и сервером.

О, и не забудьте включить версию протокола в приветственный пакет. Получение билета на проблемы с «Мое клиентское приложение говорит, что я не поддерживаю версию 2 протокола» лучше, чем «Некоторые из клиентов работают нормально, но когда я пытаюсь получить набор данных, все, что я получаю, являются случайными числами!».

+0

+1 для версии протокола, +2 если можно было посмотреть на чужие спецификации ... –

Смежные вопросы