Pull to refresh

Танчики в консоли, статья четвёртая: «Новый сервер — новый протокол»

Reading time4 min
Views3.8K
Добрый день, дорогие читатели. Мы были на WorldSkills (чему я посвящу отдельную статью) в связи с чем эта публикация долго не писалась, так же как и не обновлялся сервер.

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

Так вот, начнём с протокола TCP/IP. Чем хорош этот протокол: защищённое соединение, обеспечивающее целостность в доставке пакетов, надёжность и безопасность. Я тоже долгое время так думала, пока не произошло страшное… на определённом этапе работы у меня отвалилась виртуалка (т.е. клиент) и сервер зациклился сам на себе. Он просто отправлял себе пакеты на один порт, принимал что-то другим, складывал пакет+пакет (т.е. буквально, добавлял в конец первого данные начала второго, а иногда и все данные второго) и отсылал себе на порт приёма, потом принимал, потом отсылал себе снова и это очень ело ресурсы (от слова 100%).

Я решив найти ответы в интернете, ответы в конечном счёте не нашла и разочаровавшись в этом протоколе стала просить друга помощи в создании нового протокола, на базе UDP.

Часть 1: «Изменения на сервере»


Перед тем как перейдём к UDP протоколу, я хочу рассказать об изменениях на сервере:

1. Было реализовано нормальное разпоточивание клиентов (что не удавалось ранее).
2. Добавлена более адекватная (на мой взгляд) модель взаимодействия с клиентами.

Сразу перекинусь на второй пункт, так как реализовав его я смогла добиться реализации первого. Раньше я по глупости своей создавала поток, который создаёт поток, который создаёт потоки и отправляет всем сообщения… это было не правильно в корне. На данный момент всё работает по этой схеме:

image

Пожалуй это самая адекватная модель взаимодействия, которая была вытащена из моей головы.
И при приёме, и при отправке соединение не рвётся, а копируется и отправляется.

Взаимодействие происходит по принципу: услышал-отправил. Не происходит не какой конвертации или проверки данных, но периодически происходит проверка на жизнеспособность клиента (чтобы нам не уходить в вечный цикл). Это происходит по задаваемому параметру — количество выполненных чтений (сколько раз мы слышали от клиента сообщения).

Если он достигает нужной отметки, то на клиента отправляется сообщение спрашивающее жив ли он

    match item.stream.write(b"you") { 
    Ok(ok) => {}, Err(e) => {/* Выходим из приёма */ break;}
    , };

И если мы принимаем от него ненулевое сообщение, то заканчиваем проверку и слушаем как и раньше

    let mut buf_q:[u8; 256] = [0; 256]; 
    let mut buf_q_else: [u8; 128] = [0; 128];
	
    let mut recv_val = false;
        let mut b_false_true = false;
	loop {
		    item.stream.read(&mut buf_q);
		    if buf_q.starts_with(&buf_q_else) { 
				recv_val = recv_.recv().unwrap(); 
				if recv_val == true { 
					      b_false_true = true; break;  } }						
					}
			if b_false_true == true { break;} /*  это всё в ещё одном loop цикле, который и заставляет поток не завершаться и слушать клиента дальше */

Слушаем клиентов

    item.stream.read(&mut buf); println!("Принимаем сообщения [{:?}]", item.stream);
    if buf.starts_with(&q) == false { sender_clone.send(buf).unwrap(); }
/* где q - пустой байтовский массив (проверка нужна для того чтобы не передавать пустые сообщения всем клиентам) */

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

Часть 2: «Краткая теория сетевых протоколов»


Я не буду разбирать дебри системы OSI, а скажу следующее — есть два вида транспортных сетевых протоколов (на которых строятся все остальные):

1й. TCP/IP
2й. UDP/IP

Что первый, что и второй строятся на протоколе IP (поэтому и появляется '/IP').
Обсудим плюсы и минусы обоих

TCP/IP


+ поочерёдная отправка пакетов
+ базовое шифрование (методом случайного числа)
+ повторный запрос в случае искажения пакета
+- малые порции отправки

— медленная скорость
— тройное рукопожатие при коннекте и двойное подтверждение доставки
— много других не видных на первый взгляд ошибок (с одной из них я и столкнулась)

UDP/IP


+ скорость
+- независимость (плевать дошёл ли пакет)
+- пакет не делится на маленькие порции
+ отсутствует рукопожатие в принципе
+- нету ошибок (нету их определения, пакет просто извергается извне и летит… куда глаза его байтные глядят)

— нет очерёдности
— возможны искажения (т.к. нету проверки)
— нет шифрования

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

Глава 3: «Строим модель и подводим итоги»


Начнём с начала: что нам надо?

1. Стабильное соединение с клиентом (TCP)
2. Высокая скорость передачи данных (UDP)
3. Высокая скорость первоначального соединения (UDP)
4. Понимание как это работает
5. Не должно быть искажений и должна быть очерёдность (TCP)

Два TCP и два UDP свойства. Разве стоила одна ошибка в TCP (на данный момент исправленная в проекте) создание подобия TCP но со своими заморочками? Мой ответ — да!

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

Структура данных пакета

image

Схема работы сервера на будущем протоколе на этом изображении:

image

Тем самым мы получаем простую схему работы, клиент подключается — мы передаём его в общий таймаут и при каждой отправки сообщения ждём подтверждения приёма у клиента, при этом работая с остальными клиентами.

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

Теоретически получился тот же велосипед, что и на TCP, только без тройного рукопожатия и без деления пакетов на маленькие порции, что я считаю победой.

Увидеть это вы сможете совсем скоро в моём гитхабе.

Спасибо за прочтение и всего вам наилучшего!
Tags:
Hubs:
Total votes 18: ↑13 and ↓5+8
Comments6

Articles