Введение. TCP/IP.

Зачем нужны компьютерные сети?

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

  • Стриминговые сервисы, передающие на ваше устройство медиа контент (Netflix, Spotify, Яндекс музыка, Youtube, Twitch)
  • Социальные сети и месенджеры (VK, Telegram, email, Element)
  • Вэб порталы и магазины (Сайт гос услуг, Aliexpress)
  • Он-лайн игры
  • Обновления ОС или программ

Но есть и чуточку более абстрагированные случаи:

  • Системы платежей (Visa, MasterCard, МИР)
  • Удалённое управление (рабочие места, домофоны, квадрокоптеры)
  • Промышленность (системы управления заводом, складом)

Ожидания

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

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

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

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

Следующее ожидание на примере использования системы оплаты в качестве потребителя сложно прочувствовать. Намного проще на него посмотреть со стороны банка. У вас, как у потребителя услуг в банка одновременные взаимоотношения с единицами банков, а клиентов у банка могут быть миллионы. Очень большое количество клиентов может провести какую-нибудь операцию примерно в одно время. Чтобы сохранить репутацию надёжного банка, его сервисы должны быть достаточно производительны, чтобы обслужить всех.

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

Всё это произошло не случайно. Залогом успеха взаимодействия сложных систем является чёткое описание взаимодействий. Одна из форм такого описания - протокол.

Протоколы

Их критически важно отличать от реализации и интерфейса.

Протокол: В нашем случае под протоколом мы подразумеваем набор действий и правил, например, последовательности этих действий. Чаще всего это текстовое, а иногда и графическое описание. Известным примером протокола является HTTP, а тестовое описание его версии 1.0 можно найти в RFC 1945.

Пример псевдографической составляющей мы берём из RFC 791, оисывающего Internet Protocol:

  0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version|  IHL  |Type of Service|          Total Length         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Identification        |Flags|      Fragment Offset    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Time to Live |    Protocol   |         Header Checksum       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Source Address                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Destination Address                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                    Example Internet Datagram Header

Реализация: На примере всё того же HTTP, его реализуют почти все браузеры. Если покопаться в исходных кодах FireFox или Chromium, то можно найти части, ответственные за обработку HTTP. Они будут отличаться. И именно эти части и являются реализацией. Другой интересный пример реализации HTTP - curl

Интерфейс: Обсуждая реализацию мы упомянули разные браузеры. Адресные строки в них выглядят чутка по разному, но не это отличие нас интересует в этом контексте. Нам важно знать, как отличается интерфейс от реализации.

Вот пример адресной строки из FireFox:

Изображение адресной строки браузера

В ней протокол https и сам адрес стоят вместе, отсутствуют тип запроса и порт подключения. И это удобный нам, пользователям браузера, формат. Однако сам HTTP выглядит иначе, рассмотрим первые две строчки HTTP запроса:

GET / HTTP/2
Host: insysnw.github.io

Это помогает нам понять

  • написанный по спецификации протокола код может сильно различаться, но корректно работать, ведь в нём описана одна логика. TODO: перефразировать.
  • То, что видит пользователь не обязано напрямую соответствовать протоколу и наоборот
  • Код не является спецификацией протокола TODO: подвести к этому

Основа современного интернета

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

Первой заметной инициативой по созданию такого разбиения была модель OSI (Open Systems Interconnection).

Ниже приведены все 7 уровней этой модели:

ПрикладнойApplication
ПредставленияPresentation
СеансовыйSession
ТранспортныйTransport
СетевойNetwork
КанальныйData link
ФизическийPhysical

Как работает такое разбиение? Инкапсуляция! То есть вложение вышестоящего уровня в нижестоящий (путём добавления спереди заголовка нижестоящего уровня и изредка окончания).

Как это помогает? Это изолирует спектр проблем в конкретный уровень. Что в свою очередь позволяет разработчику сосредоточить усилия на бизнес логике. Так разрабатывая свой web-сервер не приходится думать о том, пользуется ли клиент WiFi или подключен к сети оптоволокном.

К слову, мы только что задели второй важный аспект разбиения на уровни. Протоколы в рамках одного уровня можно заменять. Не всегда это так просто как с WiFi и оптоволокном и влечёт изменения в других уровнях. Но даже при этом изменения не затрагивают весь стек.

Хотя все уровни в модели OSI выглядели логичными, в далёкие времена её создания, бизнесу востребованными казались не все. И до окончания длительной разработки OSI, на сцену выходит актуальный и по сей день стек TCP/IP.

В нём были отброшены два уровня: представления и сеансовый. Тем не менее, их отсутствие в стеке не значит отсутствие проблем. Это привело к миграции решения этих проблем в другие уровни. Так сеансовый уровень можно встретить в транспортном (протокол TCP, PPTP) и в прикладном (протокол HTTP). А уровень представления ярко выражен в прикладном: шифрование - TLS, отображение - Unicode, сжатие в теле HTTP пакета.

Ниже приведены уровни модели TCP/IP (зачёркнутые приведены для демонстрации разницы с OSI)

ПрикладнойApplication
ПредставленияPresentation
СеансовыйSession
ТранспортныйTransport
СетевойNetwork
КанальныйData link
ФизическийPhysical

В рамках этого курса мы обсудим все уровни кроме физического и канального.

Сокеты

Обсудив исключительно теоретическую часть, начнём приближаться к практике! А на практике для организации сетевого сообщения Операционные Системы(OC) предоставляют программистам особый инструмент - сокеты (англ. socket)

TODO: изображение глазного яблока / розетки / CPU socket / Ethernet socket

На картинках мы увидели разные типы разъёмов, все они в английском языке обозначаются словом socket. Те сокеты, что предоставляет нам OC, это абстракция, предоставляющая виртуальный разъём, в который можно подключить какое-то соединение.

Сокеты зародились в мире UNIX подобных систем, где ярко выражена философия “всё файл”. Так и сокет в этих системах - файл. Его можно создать специальным системным вызовом, а потом писать и читать так, как вы делаете это с обычным файлом! Однако гораздо удобнее и эффективнее использовать для чтения и записи системные вызовы предназначенные специально для работы с сокетами. Скоро мы и до них доберёмся.

Мы обсудили, что в сокеты можно подключать какие-то соединения. Какие?

Устанавливая розетку у себя дома, мы сначала выбираем её тип (шотке (TODO: дать ссылку и привести другие примеры)). Так и для сокета необходимо выбрать тип (семейство), указывается при создании сокета. Список семейств, поддерживаемых Linux можно увидеть в man 7 address_families, но посмотришь лишь на некоторые из них.

UNIX сокеты являются популярным средством IPC и активно упоминаются на курсах Операционных Систем. Это отличным пример исключительно локального сокета, т.е. сетевые соединения с его помощью не возможны, поэтому оставим его рассмотрение.

Bluetooth - знакомая многим из вас беспроводная технология.

IR - инфракрасный порт, сейчас чаще всего встречается в пультах дистанционного управления. Для него есть сокет, ведь вы можете захотеть управлять кондиционером со своего Android телефона!

Вот мы добрались до двух главных в этом курсе семейств: IPv4 и IPv6. Именно они являются основным языком всемирной паутины.

Знакомство IPv6 в этом курсе ещё не подготовлено, так что погрузимся в мир IPv4. Хоть эти два семейства отличаются достаточно сильно, чтобы иметь разные типы сокетов, вполне возможно писать код, который работает сразу с обоими.

IPv4

Начнём разбор с IP пакетов, то есть сетевого уровня. Это первый уровень на котором возникает возможность адресовать возможность адресовать сетевой узел за рамками прямой видимости. Но с этим и возникает первая проблема!

Как адресовать другой узел?

Для этого было решено выделить 32 бита, а для удобства разбить их на 4 октета. Для представлению человеку был выбран формат отображения каждого октета в десятичной системе и разделения их точками. Например:

192.168.1.1

Для компьютера такое представление является строкой, что требует больше памяти, проверок и вычислительных ресурсов, чем, например, uint32, вмещающий ровно 32 бита.

Вы, наверное, уже заметили и готовы упрекнуть меня. “Адрес обычно выглядит иначе!”

192.168.1.1/24 или 192.168.1.1 и его маска 255.255.255.0.

И тут вы правы! Свой адрес мы часто обозначаем именно таким образом. К слову, две вышестоящих записи равносильны. Обе имеют адрес и маску подсети, просто записаны в разной форме.

Сначала разберёмся, что такое маска, а потом вернёмся к правилам её записи.

А маска это третий по счёту способ определения принадлежности адреса к сети. До неё сеть определяли по классy(от 1 до 3 первых байт). А ещё раньше по первым 8 битам.

К счастью об этом теперь можно смело забыть, ведь теперь есть CIDR, т.е. те самые маски подсети.

Стоп! Как забыть? Раньше сеть хранилась в IP пакете в поле адреса, а теперь появилась маска подсети - отдельное значение. Где оно хранится?

TODO: изображение IP пакета

Мы видим, что новое поле для маски подсети не появилось. Это значит, что в IP пакете маски подсети нет! А так как нужна она для маршрутизации, там мы её и рассмотрим.

Типы сокетов IPv4

Ранее мы договорились, что сокет - абстракция. Это значит, что абстрагируя IPv4 в сокет можно что-то потерять! И так оно и произошло, потерялись названия протоколов транспортного уровня. Создавая сокет, вы не увидите аббревиатуры UDP или TCP. НО! Верно отражена суть происходящего.

ОС предоставляет нам три вида сокетов:

  • STREAM
  • DGRAM (datagram)
  • RAW

Рассмотрим их с точки зрения сложности использования программистом.

Stream (потоковые) сокеты - самые простые из представленных. Скрывают за собой протокол транспортного уровня - TCP. Такие сокеты создают надёжные двунаправленные потоки между двумя узлами. Это позволяет почти беззаботно писать в сокет и читать из него. Что такое “надёжные”? Нет, это не абсолютно устойчивые ко всему соединения, в том числе полному отключению сети или хотя бы её смене (Wifi <-> Мобильное соединени). Конкретное значение увидим в Datagram сокетах.

Datagram сокеты оперируют блоками данных и в целом всё. Название пришло от скрываемого за ними протокола - User Datagram Protocol. В такие сокеты тоже можно просто писать и читать. И это даже будет работать. Но ровно до тех пор, пока ваша сеть идеальна, а данные не вылезают за границы размера пакета. До этого потоковые сокеты позволяли совсем не думать о пакетах, ведь там ядро реализовывало всю логику TCP само, а нам, программистам выдавало уже готовые данные. Поток ничем искусственно не ограничен и может быть бесконечно длинным. С блоком данных - будь добр, уложись в ограничения одного пакета!

Велика беда, разбей большой блок на маленькие и передай? К сожалению, нет. Пакеты по пути могут потеряться, продублироваться или даже перемешаться. Обо всём этом теперь нужно думать программисту. Но пакеты ещё ведь могут и повредиться? Это - то немногое, что UDP позволяет проверить. В пакете может быть хэш данных и заголовка, но в версии IPv4 оно не обязательно.

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