Рубрики
Без рубрики

Как интернет говорит

Автор оригинала: Zaid Humayun.

История об общении

Вы когда-нибудь задавались вопросом, как на самом деле говорит Интернет? Как работает один компьютер «разговаривает» на другой компьютер через Интернет?

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

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

Введите разъем

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

Как и все остальные вещи в информатике, розетка – очень абстрактная концепция. Таким образом, вместо того, чтобы определить, что такое сокет, это гораздо легче определить, что делает сокет.

Итак, что делает сокет? Это помогает двум компьютерам общаться друг с другом. Как оно работает? У него есть два метода, которые называются Отправить () и Recv () для отправки и получения соответственно.

Хорошо, это все здорово, но что делать Отправить () и Recv () на самом деле отправить и получить? Когда люди двигают рот, они обмениваются словами. Когда розетки используют свои методы, они обмениваются битами и байтами.

Давайте проиллюстрируем методы с примером. Допустим, у нас есть два компьютера, A и B. Компьютер A пытается сказать что-то на компьютере B. Поэтому компьютер B пытается слушать то, что говорит компьютер. Вот что это было бы похоже.

Чтение буфера

Выглядит немного странно, не так ли? Для одного обои компьютеры указывают на бар в середине, названном «буфере».

Что такое буфер? Буфер – это стек памяти. Это где хранятся данные для каждого компьютера и выделяются ядром.

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

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

#Computer A sends data computerA.send(data) 
#Computer B receives data computerB.recv(1024)

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

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

Почему я выбрал 1024 байта, чтобы получить сразу? Нет конкретной причины. Обычно лучше указать количество байтов, которые вы получите в мощности 2. Я выбрал 1024, что 2¹⁰.

Итак, как буфер определяет это? Ну, компьютер пишет или отправляет, какие данные хранятся с ним в буфер. Компьютер B решает прочитать или получать первые 1024 байта о том, что хранится в этом буфере.

Хорошо, потрясающе! Но как эти два компьютера знают поговорить друг с другом? Например, когда компьютер пишет в этот буфер, как он знает, что компьютер B собирается забрать его? Чтобы перефразировать это, как он может обеспечить, чтобы соединение между двумя компьютерами есть уникальный буфер?

Портирование в IPS.

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

Рассмотрим длинный бар перед каждым компьютером, чтобы быть маршрутизатором, который подключает определенный компьютер к Интернету. Эти номера, перечисленные на каждом баре, называются Порты Отказ У вашего компьютера есть тысячи портов, доступных на нем прямо сейчас. Каждый порт позволяет соединением сокета. Я только показал 6 портов на изображении выше, но вы получите идею.

Порты ниже 255 обычно зарезервированы для системных вызовов и низкоуровневых соединений. Как правило, рекомендуется открыть соединение на порту в высоких 4 цифрах, таких как 8000. Я не нарисовал буфер на изображении выше, но вы можете предположить, что каждый порт имеет свой собственный буфер.

Сама бара также имеет номер, связанный с ним. Этот номер называется IP-адресом. IP-адрес имеет кучу портов, связанных с ним. Подумайте об этом следующим образом:

                          127.0.0.1                             / | \                            /  |  \                           /   |   \                        8000  8001 8002

Отлично, давайте настроим подключение к определенному порту между компьютером A и компьютером B.

# computerA.pyimport socket 
computerA = socket.socket() 
# Connecting to localhost:8000 computerA.connect(('127.0.0.1', 8000)) string = 'abcd' encoded_string = string.encode('utf-8') computerA.send(encoded_string)

Вот код для ComputerB.py.

# computerB.py import socket 
computerB = socket.socket() 
# Listening on localhost:8000 computerB.bind(('127.0.0.1', 8000)) computerB.listen(1) 
client_socket, address = computerB.accept() data = client_socket.recv(2048) print(data.decode('utf-8'))

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

Я произвольно выбрал A для отправки данных и B для получения данных. В этой линии computera.connect (('127.0.0.1', 8000) Я делаю Computera Connect к порту 8000 по IP-адресу 127.0.0.1.

Тогда для ComputerB я делаю его связываться с портом 8000 по IP-адресу 127.0.0.1. Теперь вы, вероятно, задаетесь вопросом, почему у меня есть тот же IP-адрес для двух разных компьютеров.

Это потому, что я изменяю. Я использую один компьютер, чтобы продемонстрировать, как вы можете использовать сокеты (я в основном подключаю к тому же компьютеру ради простоты). Обычно два разных компьютера будут иметь два разных IP-адреса.

Мы уже знаем, что только биты могут быть отправлены как часть пакета данных, поэтому мы кодируем строку перед отправкой его. Аналогично, мы декодируем строку на компьютере B. Если вы решили запустить два файла с двумя файлами, убедитесь, что запустите ComputerB.py файл сначала. Если вы запустите computera.py Файл сначала вы получите сообщение об ошибке.

Служит клиентам

Я уверен, что многие из вас были довольно ясны, что я так далеко описываю, это очень упрощенная модель клиент-сервер. На самом деле вы можете увидеть это с вышеуказанного изображения, все, что я сделал, заменяет компьютер A в качестве клиента и компьютера B в качестве сервера.

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

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

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

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

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

ARR = [«Случайные», «струны», «что», «нужны», «до», «будь», «перенесены», «через», ««, «сеть», «Использование», «сокеты» Несомненно

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

Так, например, если клиент собирается отправить через строку «случайным», и давайте предположим, что каждый символ занимает 1 байт, то сама строка занимает 6 байтов. 6 байтов тогда равны битам. Поэтому для String «Remand» для передачи через разъемы от клиента на сервер, сервер должен знать, что он должен получить доступ к 48 битам для этого определенного пакета данных.

Это хорошая возможность сломать проблему вниз. Есть пара вещей, которые нам нужно сначала понять.

Как мы выясним количество байтов строковую занятую в Python?

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

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

Лен («Random'.Encode» («UTF-8»)) даст нам то, что мы хотим

Как мы отправляем количество байтов, занятых каждой строкой на сервер?

Легко, мы конвертируем количество байтов (которое является целым числом) в двоичное представление этого номера и отправить его на сервер. Теперь сервер может рассчитывать на получение длины строки перед получением самой строки.

Как сервер знает, когда клиент закончил отправку всех строк?

Помните из аналогии разговора, должен быть способ узнать, завершен ли передача данных. Компьютеры не имеют собственной эвристики, на которых они могут положиться. Итак, мы предоставим случайное правило. Мы скажем, что когда мы отправляем через строку «End», что означает, что сервер получил все строки и теперь может закрыть соединение. Конечно, это означает, что мы не можем использовать строку «конец» в любой другой части нашего массива, за исключением самого конца.

Вот протокол, который мы разработали до сих пор:

Длина строки будет 2 байта, а затем фактическая строка, которая будет переменной длиной. Он будет зависеть от длины строки, отправленной в предыдущем пакете, и мы будем чередоваться между отправкой длины строки и самой строки. EoT обозначает конец передачи, и отправка строки «End» означает, что больше нет данных для отправки.

Давайте покончить с этим. Я включил комментарии в коде ниже, так что это самоуверенно.

Отлично, у нас есть клиент. Далее нам нужен сервер.

Я хочу объяснить несколько конкретных линий кода в вышеупомянутых циклах. Первый, из CliCSocket.py файл.

len_in_bytes = (len_of_string) .to_bytes (2,)

Что вышесказанное преобразует число в байты. Первый параметр, переданный функции to_bytes, – это количество байтов, выделенных к результату преобразования len_of_string к его двоичному представлению.

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

Следующая строка кода я хочу взглянуть на:

client_socket.send (string.encode (‘utf-8’)))

Мы преобразуем строку в двоичный формат, используя 'UTF-8' кодирование.

Далее, в serversocket.py файл:

data = client_socket.recv(2) str_length = int.from_bytes(data, byteorder='little')

Первая строка кода выше получает 2 байта данных от клиента. Помните, что когда мы преобразовали длину строки в двоичный формат в CliCSocket.py Мы решили сохранить результат в 2 байтах. Вот почему мы читаем 2 байта здесь для тех же данных.

Следующая строка включает преобразование двоичного формата в целое число. BYTEORDER Вот “мало”, чтобы соответствовать BYTEORDER Мы использовали на клиенте.

Если вы пойдете вперед и запустите два розетка, вы должны увидеть, что сервер будет распечатать строки, которые клиент отправляет поперел. Мы установили связь!

Заключение

Хорошо, мы накрыли довольно немного. А именно, что такое розетки, как мы их используем и как разработать очень простой и глупый протокол. Если вы хотите узнать больше о том, как работают сокеты, я настоятельно рекомендую читать Руководство Beej к сетевой программированию Отказ Эта электронная книга имеет много отличных в нем.

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

Если вы хотите, вы можете следовать за мной на Твиттер или же Гадость Отказ Вы также можете проверить мой блог здесь Отказ Я всегда доступен, если вы хотите добраться до меня!

Первоначально опубликовано https://redixhumayun.github.io/networking/2019/02/14/how-the-internet-speaks.html 14 февраля 2019 года.