Что происходит, когда вы открываете веб-сайт в браузере?

Жизнь. Одно из самых сложных понятий, когда-либо известных человечеству. Когда мы пытаемся описать жизнь, мы обычно начинаем с живых организмов, таких как мы, люди (я прошу прощения у роботов, читающих эту статью, за технорасовую дискриминацию). Мы состоим из клеток, и взаимодействие этих клеток дает результаты, которые мы называем «решениями», «дыханием», «мышлением», «сном» и т. Д. Сама жизнь основана на очень простой, но фундаментальной концепции, называемой «общением». ; клетки, органы, люди, животные, природа, сообщества, города, страны (сто лет спустя планеты, галактики, мир) - все они общаются и поддерживают баланс между порядком и хаосом. Не будет большим преувеличением принять во внимание биты при описании коммуникации. Сигнал - ключевое понятие в коммуникации. Вы общаетесь со светом, включая или выключая выключатель, тем самым подавая сигнал на лампочку. Свет возвращается, включая или выключая. Он может просто проигнорировать запрос, сигнализируя о своей смерти, или об отсутствии электричества, или об отключении проводов, соединяющих выключатель со светом, и так далее.

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

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

Браузер и ОС

Веб-браузер - это программа, используемая для доступа к веб-сайтам по всему миру. Прежде чем вы начнете вводить адрес веб-сайта, который хотите посетить, вам необходимо запустить приложение браузера (очевидно). Когда вы нажимаете значок браузера с помощью мыши / трекпада для его запуска, операционная система распознает щелчок мышью в определенной области экрана. В ОС также есть координаты всех прямоугольников значков, размещенных на вашем рабочем столе. Двойной щелчок (или одиночный щелчок, как установлено в настройках вашей ОС) заставляет ОС искать программу в файловой системе. Программы обычно находятся в определенном каталоге (например, /usr/bin), когда ОС находит файл программы, который является просто файлом, который отличается от других файлов, таких как acdc-hellsbells.mp3, своим форматом , расширение и содержимое. Файл, который можно запустить, называется исполняемым файлом, поэтому в некоторых системах его расширение - .exe (в Windows). Браузер - это файл, который может быть выполнен ОС, поэтому он содержит инструкции, которые заставляют ОС делать то, что браузер хочет от нее.

ОС загружает содержимое инструкций программы браузера в основную память, которая называется RAM ( оперативная память ) или DRAM ( динамическая RAM ). Она называется основной памятью, потому что служит местом, где расположены инструкции и данные, и к ней может получить доступ ЦП, который, в свою очередь, является единственным человеком, который может что-либо выполнять. Сама ОС (которая загружает содержимое браузера в память) запускается процессором.

ЦП (центральный процессор) - это небольшое устройство, способное одновременно выполнять простые инструкции, включая чтение данных из памяти, запись данных в память, выполняя арифметические и логические операции и т. д. ЦП имеет небольшие блоки памяти, называемые регистрами, в которых хранится фиксированный объем данных (например, 4 байта), называемый словом. Слово - это имя блока данных, который ЦП может обрабатывать за раз. «Одновременная обработка» называется циклом ЦП. Это похоже на жевательную резинку. Вы двигаете ртом так, что ваши верхние и нижние зубы сближаются, и, в конечном итоге, давите на десну внутри них, чтобы открыть сладкий сок, который ваш язык ощущает своими рецепторами, и сигнализирует вашему мозгу, что это вкусно, и вы чувствуете себя немного лучше. Каждый раз, когда ваши верхние и нижние зубы встречаются друг с другом и натягивают десну между ними, ваш рот завершает цикл жевания. Вы закончите с жевательной резинкой, когда полностью выдавите весь сладкий вкус, который она имеет, пережевывая ее сто или тысячу раз. ЦП выполняет простое действие (обычно связанное с данными) и сохраняет результаты в регистре за один цикл ЦП. Программа состоит из множества таких действий, которые ЦП может выполнить за тысячи циклов.

Операционная система загружает содержимое программы с помощью «инструмента», называемого загрузчиком. Загрузчик копирует содержимое исполняемого файла в основную память. Когда он готов, указатель инструкции ЦП (регистр, в котором хранится текущий адрес инструкции, которая должна быть выполнена) указывает на первую инструкцию программы. Программа, т.е. е. браузер запускается. Он отображается на экране с помощью API, предоставляемого операционной системой. Рамка окна, кнопки, меню, цвета - все это отображается на экране с помощью ОС. Операционная система служит средой, в которой программы могут запускаться, не перехватывая друг друга. ОС также отслеживает действия программы, чтобы предотвратить деструктивные намерения программы (если таковые имеются). Для этого в операционной системе используется концепция процесса, то есть выполняющейся программы. Программа, находящаяся в файловой системе, «спит» до того, как загрузчик скопирует ее содержимое в память. После этого программа просыпается и запускается как процесс.

Под капотом исполняемого файла

Примечание. Я лично рекомендую эту книгу. .

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

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

Мы пишем программы на языках программирования высокого уровня, таких как C ++. Но программа, в конце концов, должна быть переведена в машинный код, который будет запускаться центральным процессором. Процесс перевода (известный как компиляция) упрощается за счет использования средних состояний перевода, то есть программа переводит на язык сборки, а затем в машинный код. Давайте посмотрим на низкоуровневое представление упомянутой выше логики.

Предположим, у нас есть функция request(), которая выполняет поисковый запрос Google или HTTP-запрос на основе результата синтаксического анализа текста, набранного в адресной строке. Мы вводим следующий упрощенный бла-код (бла-код - это смесь псевдокода и всего, что хочет автор). Допустим, мы установили для свойства url значение 1, если адрес является допустимым URL, и 0, если это не так (поисковый запрос).

void request(address) {
  if (address.url == 1) { 
    makeHTTPRequest(address); 
  }
  else { // url == 0
    makeGoogleSearch(address);
  }
}

(Очевидно, программа также определяет функции makeHTTPRequest и makeGoogleSearch где-то в коде.)

ЦП выполняет инструкции последовательно, одну за другой, а инструкции - это простые команды, выполняющие только одно действие. Мы можем использовать сложные выражения в одной строке на языке программирования высокого уровня, таком как [очевидно] C ++, в то время как инструкции сборки - это простые команды, которые могут выполнять только одну простую операцию за один цикл процессора (помните жевание?): перемещение, сложение, вычитание, XOR и т. д. ЦП извлекает инструкцию из сегмента кода памяти, декодирует ее, чтобы выяснить, что именно она должна делать (перемещать данные, складывать числа, вычитать их и т. Д.), И выполняет команду. Чтобы работать с максимальной скоростью, ЦП сохраняет операнды и результат выполнения в регистрах (воспринимайте регистры как временные переменные ЦП). Регистры - это блоки физической памяти, которые расположены внутри ЦП, поэтому доступ намного быстрее по сравнению с ОЗУ. Чтобы получить доступ к регистрам из программы на языке ассемблера, мы используем их указанные имена, такие как rax, rbx, rdx и т. Д. Команды ЦП работают с регистрами, а не с ячейками ОЗУ, поэтому ЦП должен скопируйте содержимое переменной из памяти в регистры, выполните операции и сохраните результаты в регистре, а затем скопируйте значение регистра обратно в ячейку памяти.

Например, выражение высокого уровня:

a = b + 2 * c - 1;

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

mov rax, b; copy the contents of "b" located in the memory to the register rax
mov rbx, c; the same for the "c" to be able to calculate 2 * c
mul rbx, 2; multiply the value of the rbx register with immediate value 2 (2 * c)
add rax, rbx; add rax (b) with rbx (2*c) and store back in the rax
sub rax, 1; subtract 1 from rax
mov a, rax; copy the contents of rax to the "a" located in the memory

Условный оператор предполагает, что часть кода следует «пропустить», например, вызов request(“world better place how”); означает, что if block будет опущен. Чтобы выразить это на языке ассемблера, используется идея прыжков. Мы сравниваем два значения и на основе результата переходим к указанной части кода. Мы маркируем часть, чтобы можно было «найти» набор инструкций. Например, чтобы пропустить добавление 99 в регистр rbx, мы можем «перейти» к части с меткой «MEH», используя команду безусловного перехода jpm.

mov rax, 2
mov rbx, 0
jmp MEH
add rbx, 99; will be skipped
MEH:
add rax, 1
...

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

Тело функции request() преобразуется в следующий ассемблерный код (упрощенный), где je интерпретируется как «переход, если равен», а jne как «переход, если не равен» (на основе результатов сравнения с использованием cmp инструкция):

mov rax, address.url; copy the "address.url" into the rax register
cmp rax, 1; 
je IS_URL; jump if url is 1
jne IS_SEARCH_TERM; jump if url is 0
IS_URL:
  call makeHTTPRequest
IS_SEARCH_TERM:
  call makeGoogleSearch 

Исполняемый файл браузера состоит из тысяч строк схожих кодов, но в виде нулей и единиц, где каждая комбинация определяет команду или данные (10001 означает добавить, 01101 означает перемещение и т. Д.).

Набрав адрес и нажав «Enter»!

ОС обрабатывает пользовательские события, такие как щелчок мыши или нажатие клавиши клавиатуры, и передает их работающему приложению. Когда вы щелкаете адресную строку браузера, набираете адрес веб-сайта и нажимаете кнопку «Enter», все эти события передаются браузеру операционной системой. ОС, в свою очередь, получает их от ЦП через прерывания. Прерывание - это “hey” цифрового мира. Представьте, что вы прогуливаетесь и обдумываете тему своего стартапа, цель которого - убедить инвесторов в том, что все, что вы хотите сделать, - это сделать мир лучше (вместо того, чтобы зарабатывать кучу денег и возможность расписывайтесь на сиськах ваших фанатов (которые, очевидно, являются шиком)); и кто-то прерывает вас с помощью “hey!”, вы делаете паузу в своих явно фантастических мыслях и поворачиваетесь к тому человеку, который спрашивает вас, как добраться до ближайшей станции, бла-бла. Вы отвечаете на них и возвращаетесь к своим явно фантастическим мыслям. “hey!” прерывает вас из вашей «стандартной» процедуры точно так же, как и процессор, когда пользователь что-то нажимает или набирает. Эти события затем передаются браузеру, который правильно реагирует на них, отображая буквы в адресной строке, например, когда вы печатаете.

Прерывание - это сигнал процессору, излучаемый аппаратным или программным обеспечением, указывающий на событие, требующее немедленного внимания (Википедия).

После ввода адреса, например, «facebook.com», и нажатия «Enter», сигнализирующего браузеру о начале загрузки содержимого веб-сайта, браузер начинает синтаксический анализ адреса. Большинство браузеров позволяют вам искать термин, а не вводить адрес полностью, например, в Chrome (я использую Chrome), ввод «facebook» без «.com» выполняет поиск в Google и приводит к списку веб-сайтов, наиболее соответствующих запросу, и, очевидно, первым результатом будет ссылка на facebook.com. Чтобы достичь этого, а также правильно запросить веб-сайт, браузер анализирует содержимое адресной строки, чтобы узнать, что именно. Это «asdf», или это IP-адрес (138.201.20.123), или это полностью типизированный адрес веб-сайта («http://facebook.com»)? В любой ситуации браузер «должен» выполнить сетевой запрос к целевому серверу, чтобы получить содержимое отображаемого веб-сайта.

Поиск имени

Предположим, вы набрали «http://facebook.com» и ждете ответа браузера. Браузер должен каким-то образом найти единственный сервер, содержащий содержимое веб-сайта, и попросить этот сервер отправить его содержимое. Это все равно, что искать парня по имени Валод, который живет на планете Земля и имеет татуировку с русалкой на левом плече.

Для этого браузер должен найти фактический IP-адрес сервера, который сопоставлен с именем «facebook.com». Браузер сначала выполняет поиск в DNS. DNS означает сервер доменных имен, сервер, на котором хранятся имена, сопоставленные с IP-адресами. Поиск начинается с вашего локального интернет-провайдера на так называемые корневые интернет-серверы, чтобы получить серверы имен сначала для домена верхнего уровня «.com», а затем для «facebook.com».

Браузер кэширует ответ для более быстрого доступа к тому же веб-сайту, пропуская этап поиска DNS. Обычно получение IP-адреса веб-сайта занимает микросекунды, затем браузер отправляет HTTP-запрос на сервер. Здесь начинается самое сложное.

Сетевые запросы

Как для поиска в DNS, так и для отправки HTTP-запроса на сервер браузер должен делать это через Интернет. Для этого он использует концепцию, называемую сокетами. Сокеты - это абстракции, предоставляемые операционной системой и позволяющие получить доступ к удаленному компьютеру на другой стороне планеты.

Сокеты - это способ доступа к другому миру, чтобы отправлять или получать данные из другого мира, между мирами должно быть установлено стабильное соединение с помощью сокетов. Сокеты - это файлы, которые по-разному обрабатываются ОС. Программа сообщает о своем намерении получить доступ к Интернету, сообщая ОС создать для него сокет, специальный файл, в который программа может записывать данные, которые будут передаваться по сети (также может быть локальной сетью). Всякий раз, когда программа что-то записывает в сокет, ОС передает это в указанную конечную точку (другой сокет на другом компьютере). Таким образом, браузер создает сокет (просит ОС создать его) после того, как пользователь вводит адрес веб-сайта и заполняет сокет данными, касающимися запроса. Не имеет значения, является ли запрос поиском DNS или HTTP-запросом к серверу Facebook, это происходит с использованием сокета. Тип сокета, который создает браузер, - это клиентский сокет, потому что он должен использоваться, чтобы «что-то просить». Тот, который обслуживает результаты (сервер Facebook), прослушивает входящие сетевые запросы и создает свой собственный «серверный» сокет для обработки запросов и обслуживания данных.

Как ОС справится с несколькими программами, которым требуется доступ к сети? Например, предположим, что вы открываете facebook.com в своем браузере и одновременно разговариваете со своим другом с помощью настольного приложения Skype. Оба приложения требуют подключения к сети, и оба просят ОС создать для них сокеты. В конце концов, ОС создает два сокета для двух разных приложений. Чтобы узнать разницу между этими сокетами, он использует номера портов. У каждого сокета есть свой уникальный номер порта, который не может использоваться другими приложениями. Например, сокет, созданный для Skype, использует порт 5678, а сокет, созданный для браузера, использует порт 8765. Таким образом, ОС может отличить данные, отправленные браузером, от данных, отправленных Skype, а также может правильно передать ответ к соответствующему приложению. Номер порта указывается разработчиком программы и должен быть выбран с умом.

Почему вы не можете получить доступ к Интернету с помощью карманного калькулятора

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

Чтобы передать пакет, отправитель должен как-то пометить его для получателя так же, как почта помечена марками, адресом доставки и адресом отправителя. Для этого существуют протоколы. Каждый уровень сетевой модели добавляет к пакету метаданные, зависящие от уровня. Пакеты, формируемые браузером, представляют собой документы HTTP (протокол передачи гипертекста), отправляемые через TCP (протокол управления передачей).

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

Когда вы запрашиваете содержимое facebook.com, документ-запрос не содержит тела, он содержит только заголовок, описывающий, что нужно браузеру от сервера. Сервер отвечает документом, который содержит полное содержимое запрошенной веб-страницы в теле HTTP-документа.

Итак, во время сетевого взаимодействия происходит следующее:

  • браузер создает сокет (указав номер порта, протокол передачи);
  • браузер создает документ HTTP-запроса;
  • браузер записывает HTTP-документ в сокет и дает команду ОС сделать запрос;
  • ОС преобразует данные в пакеты TCP и передает их сетевому адаптеру;
  • сетевой адаптер отправляет биты пакетов в сеть;
  • пакет (ы) принимаются от адаптера сервера, который затем передает его на более высокие уровни сетевой модели;
  • ОС сервера извлекает данные из полученного пакета и передает на веб-сервер;
  • веб-сервер анализирует содержимое как HTTP-документ и создает ответный HTTP-документ;
  • веб-сервер отправляет ответ так же, как его отправил клиент;
  • клиент получает ответ и отображает содержимое как веб-страницу.

Обслуживание запроса

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

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

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

Для обработки запроса большую часть времени требуется доступ к базам данных. Предположим, вы открыли facebook.com в своем браузере и не вышли из системы при последнем посещении. Таким образом, браузер сохранил информацию о вашей последней авторизации в своей «памяти» и теперь запрашивает facebook.com, передав эту информацию (обычно это ключ запроса в форме «kjhlkjhjhl1234324WEASDASF34534FDFGDfhhf877») вместе с HTTP-запросом (в заголовке HTTP). . Серверы Facebook авторизуют запрос и получают данные пользователя, которые сопоставлены с ключом запроса, указанным в HTTP-запросе.

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

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

Рендеринг ответа сервера

Когда браузер получает HTTP-ответ от сервера, он начинает с просмотра заголовка документа. Заголовок определяет тип содержания: текст HTML или двоичные данные для загрузки, изображение для отображения на экране и т. Д. Обычно ответ содержит HTML-текст веб-страницы. Браузер обнаруживает это, исследуя HTTP-документ на предмет заголовка Content-Type.

Тип содержимого: текст / html

Теперь браузер должен проанализировать HTML и показать кнопки, поля ввода, таблицы, ссылки, изображения и т. Д. На странице. Браузер создает так называемую модель DOM для удобного управления веб-страницей и ее отображения. DOM (объектная модель документа) определяет модель документа, которую можно представить в виде дерева, состоящего из элементов HTML.

На изображении выше показана модель DOM, созданная из следующего HTML-кода:

<html>
  <head>
    <title>My title</title>
  </head>
  <body>
    <h1>A heading</h1>
    <a href="">Link text</a>
  </body>
</html>

HTML - это декларация того, как контент должен отображаться браузером. Помимо HTML, браузер поддерживает также CSS и JavaScript. CSS определяет стиль элементов.

JavaScript

JavaScript добавляет динамичности элементам. Браузер представляет собой мини-версию ОС, в которой работает программа JavaScript. ОС на самом деле ничего не знает о JavaScript и даже о способности браузера запускать «программу». Это все равно, что снимать квартиру у кого-то и сдавать комнату кому-то другому без ведома домовладельца.

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

function checkFields() {
  let login = document.getElementById("login");
  let pass = document.getElementById("password");
  if (login.value != "" && pass.value != "") {
    document.getElementById("submit_button").value = 1;
  } else {
    document.getElementById("submit_button").value = 0;
  }
}

Браузер позаботится о коде. Он создает среду для выполнения JS и обеспечивает доступ к элементам, отображаемым из текста HTML, полученного с сервера (код JS также извлекается с сервера). Для достижения наилучшего результата браузер содержит полнофункциональную виртуальную машину JavaScript, такую ​​как Google V8. Он запускает JS, интерпретируя его (не компилируя), что означает, что инструкции выполняются одна за другой виртуальной машиной (V8). Чтобы выполнить каждую команду, она должна быть переведена в машинный код, потому что конечным исполнителем команды должен быть ЦП. Таким образом, перевод выполняется виртуальной машиной, а браузер запускает переведенный код как собственный. Подобно нашему примеру со съемом квартиры, это все равно что попросить у домовладельца запасной ключ и передать его нашему гостю, который снимает у нас комнату.

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

📝 Прочтите этот рассказ позже в Журнале.

👩‍💻 Просыпайтесь каждое воскресное утро и слышите самые интересные истории недели в области технологий, ожидающие в вашем почтовом ящике. Прочтите информационный бюллетень« Примечательно в технологиях .