Всем привет, думаю читатель, нажавший на данный заголовок, уже, возможно, догадывается, о чем примерно пойдет речь. Данная статья рассчитана на тех, у кого уже есть какое-либо понимания языков программирования (лучше если именно Ruby), а также хотя бы общие сведения о работе ОС и сети.
Данный цикл статей будет посвящен написанию с нуля без использования сторонних библиотек аналога известного фреймворка Ruby on Rails который назовем SimpleRails. Конечно, мы не будем его повторять полностью, а лишь попытаемся повторить основные функциональные возможности.
Для тех, кто не в курсе в мире веб разработки существует фреймворк Ruby on Rails. Фреймворк горячо любим автором и сообществом и используется для создания полнофункционального сайта или по-другому веб приложения. Но все ли знают и понимают, как оно там вообще работает?
Как говорил классик – позвольте мне 30 секунд исторической справки. Все примерно слышали, что сайты работают через протокол HTTP/ HTTPS. Для упрощения возьмем протокол HTTP. Данный протокол текстовый (и работает поверх протокола TCP описание работы которого мы опустим), но что нам это говорит? По сути, это просто строка, в которой определенным способом хранится информация. То есть, по сути, вся работа сайта — это отправка и получение строк в определенном формате. Вот и все. Возможно, для кого-то это покажется слишком простым, но так оно и есть. Когда вы открыли сайт, на самом деле вам пришла текстовая строка, которую браузер обработал и вам отобразил.
Простейшая схема будет выглядеть так. Здесь HTTP request и HTTP response это просто строки. Верхняя отправляется на сервер, где находится сайт (пока опустим сетевые моменты). Когда вы у себя в браузере вводите название сайта или нажимаете на его ссылку — вы отправляете строку на сервер о желании получить страничку сайта, сервер отправляет вам строку с этой страничкой.
Что же за строки такие отправляются и что из себя по итогу представляет этот HTTP протокол?
Простейший запрос GET GET /customers/42 HTTP/1.1 Простейший запрос POST POST /customers HTTP/1.1 Content-Type: application/x-www-form-urlencoded Content-Length: 38 email=test@acme.com&password=pass123
P.S. пример запросов любезно взят с сайта
Запрос может содержать разные части — Разберем сначала GET запрос (интерпретация будет вольная, за точной можно отправиться за соответствующим RFC). В первой строке сначала указывается метод запроса (GET), затем путь до ресурса (/customers/42), который мы хотим получить, и затем версия самого протокола (HTTP/1.1). Запрос может быть и сложнее, как например предоставленный далее POST запрос. Аналогичным образом у него формируется первая строка, но затем идут еще несколько строк. Сначала идут строки заголовков (7 и 8 строки), а затем тело запроса (10 строка). Строки разделяются между собой символами \r\n.
С самими запросами разобрались, но кто их шлет и какими средствам получает?
Поскольку мы работаем на компьютере, на нем установлена та или иная ОС. У основных широко используемых ОС, на которых есть возможность сетевого взаимодействия есть понятие сокетов. Согласно определению википедии сокет — это программный интерфейс для обеспечения обмена данными между процессами. Возможно все равно не до конца понятно. Для большего упрощения будем считать, что сокет — это буфер, в который можно записать или считать строку.
Возьмем аналогию с кассой в банке. Как там происходит взаимодействие? Вы идете в банк, просите вас обслужить в кассе, подходите к окну с деньгами и документами, кладете их в специальный ящик и ждете пока оператор за окошком их обработает и вернет вам обратно тоже деньги или документы. С сокетами также, вы «идете» к операционной системе, просите дать вам сокет, ОС предоставляет вам сокет, вы в него пишете свою строку, ждете и получаете другую строку.
Вернемся к реализации. Взглянем на вырезку из документации Ruby.
# A simple server might look like this: require 'socket' server = TCPServer.new 2000 # Server bound to port 2000 loop do client = server.accept # Wait for a client to connect client.puts "Hello !" client.puts "Time is #{Time.now}" client.close end # A simple client may look like this: require 'socket' s = TCPSocket.new 'localhost', 2000 while line = s.gets # Read lines from socket puts line # and print them end s.close # close socket when done
Немного разберем данный код. В коде сервера мы сначала подключаем гем с сокетами, затем просим ОС открыть новый сокет на определенном порту, затем в цикле начинаем ожидать получения данных. После получения данных мы пишем обратно пару строк кода с текущем временем и отправляем их обратно. В коде клиента все работает схожим образом. Мы также подключаем гем с сокетами, затем просим ОС подключиться к существующему сокету на определенном порту, затем запрашиваем данные у сервера, печатаем их в консоль и закрываем подключение к сокету. Можно провести соответствующие аналогии с примером с банком выше.
Сверху уже вполне работающий код сервера. К сожалению, он не удовлетворяет требованию формата HTTP, но мы можем его проверить запустив клиентский код. Немного дополним его для удовлетворения требованиям формата HTTP.
require 'socket' server = TCPServer.new 2000 puts "server started" while session = server.accept puts 'get request' session.print "HTTP/1.1 200\r\n" session.print "Content-Type: text/html\r\n" session.print "\r\n" session.print "<p>Hello from SimpleRails!</p>" session.close end
Этот код уже можно запустить и получить ответ в браузере. В нем мы отправляем ответ клиенту/браузеру тоже в формате HTTP. Сначала указываем версию протокола и код возврата (200), затем пишем заголовок о том, что формат данных будет текст или html и затем сами данные в формате html.
Но почему мы не пишем наши приложения таким образом? Почему никогда не залезаем в такие дебри? Можно, конечно, в этом одном файлике вручную обрабатывать каждый приходящий пакет, но это выйдет слишком сложно, получится непонятное месиво не поддерживаемого кода. В результате были придуманы некоторые абстракции, которым будут посвящены следующие статьи.
ссылка на оригинал статьи https://habr.com/ru/articles/859066/
Добавить комментарий