Как поднять сервер на python

Python: реализуем веб-сервер своими руками

Intro
Пакет http

Как выяснилось, сам интерпретатор уже имеет в своем составе пакет http, в котором сосредоточены все функции работы с этим протоколом: как серверные, так и клиентские, в виде отдельных модулей. Так как мы пишем сервер, то нас в первую очередь интересует модуль, отвечающий именно за функции обслуживания http-запросов: в Python 3 они объединены в один модуль под названием http.server, в Python 2 эти функции разнесены по трем модулям: BaseHTTPServer, CGIHTTPServer и SimpleHTTPServer.

Обработчик запросов: BaseHTTPRequestHandler

Для реализации простого сервера будет достаточно использовать «класс-заготовку» — BaseHTTPRequestHandler. Этот класс может использоваться как базовый для реализации собственного обработчика запросов, действующего в составе сервера HTTP. После того как клиент установит соединение и HTTP-заголовки его запроса будут проанализированы, выполняется попытка вызвать метод вида do_REQUEST, имя которого определяется исходя из типа запроса: для обработки GET-запроса типа будет вызван метод do_GET(), для обработки POST-запроса – метод do_POST() и так далее. По умолчанию этот класс ничего не делает, и предполагается, что эти методы должны быть переопределены в подклассах. В простейшем случае требуется реализовать лишь метод do_GET():

from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer

Теперь необходимо создать объект класса HTTPServer, передав ему в качестве параметров IP-адрес и порт, на котором будет работать http-сервер, а также наш класс-потомок BaseHTTPRequestHandler, который собственно и будет отвечать за обработку запросов к серверу:

serv = HTTPServer((«localhost»,80),HttpProcessor)
serv.serve_forever()

Первой строкой мы создаем экземпляр HTTPServer, указывая ему, по какому адресу и с помощью чего обрабатывать наши http-запросы, затем, вызовом метода serve_forever(), мы указываем интерпретатору перманентно запустить веб-сервер — приложение будет работать до тех пор, пока его работа не будет прервана путем нашего вмешательства. Убедиться в его работоспособности можно, обратившись через браузер по тому адресу, который мы забиндили при написании скрипта: нашему взору предстанет веб-страница с единственной фразой — «hello».

Как это работает

Затем необходимо отправить http-заголовки, для чего используется метод send_header(), а также эскейп-посдедовательность (\r\n\r\n), которая свидетельствует о завершении заголовка ответа:

Источник

5 способов сделать Python-сервер на Raspberry Pi. Часть 1

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

Допустим, у нас уже есть супер Python-программа, делающая что-то очень важное, от мигания светодиодом до управления «умным домом» или хотя бы кормушкой для кота. Я покажу разные способы, от простого к сложному, как сделать web-доступ к такому приложению, добавив немного кода.

Статья расчитана для начинающих, профи вряд ли найдут здесь что-то кардинально новое, ну а новичкам в Linux надеюсь, будет полезно. Для тех кому интересно, продолжение под катом.

Примечание: эта статья является своего рода «экспериментом», как-то в комментариях жаловались что на Хабре недостаточно статей для начинающих. Я попытался восполнить пробел, ну а по оценкам будет видно, имеет смысл продолжать в таком формате или нет.

Настройка Raspberry Pi

Будем надеятся, что у читателя есть Raspberry Pi, которая подключена к домашней сети через WiFi или Ethernet, и читатель знает что такое IP адрес и как зайти удаленно на Raspberry Pi через SSH при помощи putty. Мы будем рассматривать так называемую headless-конфигурацию — без клавиатуры и монитора. Но перед тем, как делать что-то с Raspberry Pi, пара небольших лайфхаков.

Совет N1. Чтобы что-то удаленно делать с Raspberry Pi, на нем нужно настроить SSH, а по умолчанию он выключен. Можно пойти традиционным способом, и запустить стандартный конфигуратор, но можно сделать проще — после записи образа диска достаточно создать пустой файл ssh (без расширения) в корне SD-карты. Дальше, после загрузки Raspberry Pi, SSH будет сразу активен.

Чтобы зайти удаленно на устройство, нужно узнать IP-адрес Raspberry Pi. Для этого достаточно открыть контрольную панель своего маршрутизатора, найти там список DHCP-клиентов, скопировать оттуда нужный IP-адрес (например, это будет 192.168.1.102), и ввести команду putty.exe pi@192.168.1.102 (для Windows) или ssh pi@192.168.1.102 для Linux или OSX.

Однако, IP-адреса могут меняться, например после перезагрузки маршрутизатора, это не всегда удобно. Из этого следует Совет N2 — настроить статический IP-адрес. Для этого на Raspberry Pi выполняем команду sudo nano /etc/dhcpcd.conf, и вводим следующие настройки:

Если нужен адрес WiFi, то интерфейс будет wlan0, если Ethernet то eth0. IP-адреса разумеется, нужно тоже подставить свои. После перезагрузки убеждаемся что IP-адрес правильный, введя команду ifconfig.

Теперь все готово, можем приступать к Python. Все примеры даны для Python 3.7, т.к 2.7 уже давно устарел, и поддерживать его бесмысленно. Но при небольших изменениях кода все заработает и там, если нужно. Кстати, язык Python является кроссплатформенным — это значит что весь приведенный ниже код можно запустить и на Windows и на OSX, ну и разумеется, на Raspberry Pi. Из этого следует Совет N3 — отлаживать программу можно и на обычном ПК, а уже готовую версию заливать на Raspberry Pi. Возможно, придется лишь сделать функции-обертки для методов GPIO, все остальное будет работать.

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

Способ 1: командная строка

Самый простой способ, не требующий вообще никакого программирования.

Выбираем нужную папку на Raspberry Pi, и вводим команду:

Все, на Raspberry Pi работает файловый сервер! Достаточно зайти на страницу http://192.168.1.102:5000 и мы увидим наши файлы в браузере:

Способ 2: SimpleHTTPServer

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

Читайте также:  что относится к рептилиям

Команда os.chdir является опциональной, если мы хотим предоставить доступ из сервера к какой-то другой папке, кроме текущей.

Способ 3: HTTPServer

Это уже полноценный web-сервер, способный обрабатывать GET и POST-запросы, возвращать разные данные и пр. Но и кода разумеется, понадобится больше.

Рассмотрим минимально работающий вариант сервера:

Запускаем браузер, и видим в нем нашу HTML-страницу:

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

Добавим в HTML тег img:

Исходный файл «raspberrypi.jpg» разумеется, должен лежать в папке с программой. Добавим в функцию do_GET возможность получения файлов:

Запускаем сервер, и видим соответствующую картинку:

Вряд ли такой сервер выиграет конкурс веб-дизайна, но он вполне работает. Сервер несложно заставить отдавать более полезные данные, например возвращать информацию о работе программы. Для примера добавим обработчик для новой функции status:

Теперь мы можем открыть в браузере ссылку http://192.168.1.102:5000/status и увидеть текущие параметры системы:

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

Заключение

Все задуманное в одну часть не влезло. Вторая часть доступна по ссылке.

Важно: меры безопасности

Если для Raspberry Pi будет использоваться внешний IP-адрес, обязательно стоит помнить о мерах безопасности. Может показаться что ваш мини-сервер никому не нужен, однако сейчас не составляет труда пакетно просканировать все диапазоны IP-адресов (как пример, Украина, Австрия) и найти все доступные устройства. Так что обязательно стоит поменять пароль на Raspberry Pi, и не стоит хранить на устройстве какую-либо конфиденциальную информацию (папки Dropbox, имена/пароли захардкоженные в скриптах, фото и пр).

Источник

Запуск домашнего веб-сервера без статического IP с помощью Python

Приветствую жителей Хабра!

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

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

Недавно я решил установить веб-сервер на Rasberry Pi, работающий за моим домашним маршрутизатором. У меня есть опыт настройки веб-серверов на виртуальных машинах Linux со статическими IP-адресами, поэтому в настройке сервера apache2 на Pi нет ничего особенного, и в Интернете есть сотни руководств. Проблема только в том, что при изменении внешнего IP вашего роутера сайт сломается! Один из способов решить эту проблему — заплатить своему интернет-провайдеру за статический IP-адрес… но тогда в чём веселье?!

Во многих своих последних проектах я использовал Google Domains для покупки доменного имени и обычно запускал сайты без собственных гугловских серверов имен на отдельном VPS/«облачном сервере». Но для моего домашнего сервера я решил использовать невероятно простую в настройке функцию переадресации IP-адресов поддоменов, чтобы перенаправить базовый домен (@.example.com) на IP-адрес моего маршрутизатора (а затем настроить мой маршрутизатор на перенаправление с http портов на https порты на Pi). Тогда мне пришлось бы вручную проверять, работает ли сайт, и менять IP при необходимости. Очевидно, это не идеальный план, поэтому я решил написать скрипт для автоматизации этого процесса.

На заметку, вы можете найти полный скрипт на гитхабе или импортировать пакет Python с помощью pip install domains-api

Есть много способов проверить ваш внешний IP-адрес, и один из самых простых, которые я нашел, был через ipify API (api.ipify.org), который просто возвращает ваш общедоступный IP-адрес. При использовании Python библиотеки requests запрос выглядит следующим образом:

Вот и все, это ваш внешний IP. Легко, правда? Есть много других подобных способов получить внешний IP-адрес, но я считаю, что это самый простой.

Итак, что еще нам нужно для нашего скрипта? Нам нужно где-то хранить IP-адрес, чтобы проверять будущие запросы. Изначально я решил сохранить его в простом текстовом файле. Нам также нужен способ либо уведомить пользователя, либо обновить domain.google.com, либо и то, и другое. Первый вариант довольно легко реализовать с помощью библиотеки электронной почты для Python, поэтому я настроил её для работы с моей учетной записью Gmail следующим образом (вам нужно будет разрешить менее безопасные приложения (less secure apps) в своей учетной записи Google):

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

Теперь я мог бы заменить константу GMAIL_PASSWORD из функции уведомления на функцию read_pwd() (которая возвращает декодированный пароль), что всяко безопаснее.

Последнее, что мне нужно, чтобы программа стала эффективной, — это дописать функцию, которая свяжет всё вместе и сохранит/сравнит IP-адреса:

Бум! Это была первая реализация моей идеи. Когда я получаю уведомление по электронной почте, я могу просто изменить правила переадресации на сайте domains.google.com…

Стоп, что? Мне все еще нужно это делать самому? Конечно нет, есть способ проще!

Что ж, оказывается, есть два способа автоматизировать это — один значительно менее эффективный, но бесконечно более захватывающий, а другой довольно скучный, но бесконечно более эффективный! Я начну, как и сделал, с захватывающего и сложного способа: слышали когда-нибудь о Selenium для автоматизации тестирования веб-сайтов? Я решил написать сценарий, который будет физически входить в домены Google и перемещаться по сайту, чтобы изменить правила для меня, если и когда изменится IP. Однако это приводило к следующим проблемам:

Читайте также:  Как подсунуть профлист под шифер

Прежде всего, Google Domains (и другие сервисы Google, такие как Gmail) довольно хорошо обнаруживают автоматизацию браузера и просто не позволяют вам войти в систему через веб-драйвер Selenium. Мне посчастливилось найти этот ответ (есть и другие решения) в Stack Overflow, который предлагал войти в сам Stack Overflow с вашей учетной записью Google, прежде чем переключаться на желаемую службу Google, что действительно работало, пока я не брал под контроль браузер и при необходимости не вводил капчу. Со скриптом, запущенным на моем ноутбуке или десктопе, это замечательно — тем более, что после первоначальной проверки Captcha StackOverflow, похоже, больше не проверял тот же компьютер, поэтому после этого веб-драйвер можно было запустить в автономном режиме, но это не подходит для веб-сервера! Хотя я мог заставить веб-драйвер нормально работать с помощью PyVirtualDisplay и Geckodriver (веб-драйвер для Firefox), ему удавалось только один раз попасть на желаемую страницу «Мои домены», а в других случаях вообще не мог войти в систему из-за Captcha.

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

Так уж получилось, что у Google Domains есть API именно для той цели, которая мне нужна. Я изначально отклонил APi, когда не смог заставить его работать с правилами переадресации поддоменов, которые я использовал, не понимая, что API предназначен для изменения правил динамического DNSэта документация стала намного более понятной после того, как я настроил запись динамического DNS вместо стандартного правила «Переадресация поддоменов» (спасибо Джереми Гейлу за его отличный урок о том, как сделать что-то подобное с помощью простого сценария bash, который помог мне победить эту проблему!)

Раздел «Synthetic records» на странице конфигурации DNS Google Domains должен выглядеть следующим образом:

Затем вы получите автоматически сгенерированные учетные данные, необходимые для аутентификации с помощью API:

Теперь, зная этот метод, я смог значительно уменьшить длину и нагрузку на скрипт! TTL динамического DNS также очень низок, по умолчанию: 1 мин, что сокращает возможное время простоя — ещё один дополнительный бонус. Всё, что мне было нужно, это включить вызов API в мою функцию check_ip(), и он сделает все за меня! И эта единственная строка кода (2 с вызовом логирования) выглядит так:

Я заключил всё в блок try / except, чтобы перехватить любые исключения, и таким образом этот довольно простой, но удивительно полезный скрипт был почти готов. Теперь осталось только добавить его в crontab на моем веб-сервере и дать ему работать, и (теоретически) мне больше не придется беспокоиться о смене IP!

Стоп! … Время рефакторинга

Готовый, практически уникальный (!) результат можно увидеть ниже во всей его полноте, а также его можно форкнуть/клонировать с моего GitHub (включая README.md с инструкциями по установке). Я также выпустил его как пакет Python на pypi.org, который вы можете просмотреть здесь или установить обычным способом с помощью: pip install domains-api

Любые вопросы, отзывы или предложения — пишите!

Какие ещё методы стабильной работы веб-сервера без статического адреса вы знаете? И как можно доработать это решение?

Источник

Запускаем простейший веб-сервер на Python и Flask

Есть масса вариантов запустить собственный веб-сервер, обрабатывающий поступающие от пользователей HTTP запросы, и возвращающий результат в их браузеры. В данном примере мы рассмотрим создание такого сервера при помощи Python.

Устанавливаем нужные библиотеки

Предположим, что Python, pip и virtualenv у вас уже установлены и настроены, соответствующие статьи есть на сайте. Теперь перейдет к загрузке Flask:

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

Для проверки правильности установки, можно создать файлик server.py, в котором будет такое содержимое:

Для его выполнения воспользуйтесь командой:

С помощью Flask можно делать немало интересных штук, к примеру, осуществлять обработку GET и POST параметров.

Теперь нам нужно переработать скрипт так, чтобы он смог принять имя пользователя, а затем вывел приветствие на экране:

Мы указали, что теперь для работы скрипта будет использоваться порт 4567. Также он будет через адресную строку принимать имя от пользователя. Открываем в браузере следующий адрес: http://localhost:4567/yourname. Ответ должен быть таким: «Hello, yourname». Этим подтверждается успешная работа сервера, он вернул нужную нам строку.

Настройка прокси

Если вы хотите, чтобы вашим сайтом могли пользоваться и другие люди, вам понадобится внешний IP адрес. Разбираетесь в этом или имеете VPS? Тогда у вас не возникнет проблем с этим. Но если это для вас что-то новенькое, то прибегнем к более легкому, но не особо универсальному способу – воспользуемся прокси сервером.

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

Ответ должен состоять из нескольких строк, а среди них должно быть что-то такое:

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

Читайте также:  Мировоззрение это простыми словами что такое

Источник

Простой P2P сервер на python

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

Сегодня я хочу предложить простой вариант реализации P2P сервера для такой сети на языке python.

Предыстория

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

Самым трудным для меня оказалось написать серверную часть. Если интерфейс я написал практически сразу, на него я потратил порядка 2 дней, то над серверной частью мне пришлось подзадуматься. Думал я неделю, но зато на следующий день за пару часов написал рабочий P2P сервер для своего чата.

Сервер

Исходный код всего сервера расположен ниже.

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

Инициализация

Для инициализации сервера запросим порт, на котором будем запускать сервер и максимальное кол-во подключений, по умолчанию 1. Сам сервер будет хранить такие данные:

Листы длиной равной максимальному количеству пользователей:

Также объявим чёрный список адресов, который будет загружаться из файла и постоянно содержать адрес «127.0.0.1» во избежание «двойного подключения» к себе самому ( localhost всё ещё доступен), и словарь, который будет хранить входящие сообщения. И нужно установить серверному сокету максимальное кол-во подключений командой listen().

add функции

Все функции в этой категории будут работать только внутри класса. Неправильное обращение с ними может вызвать неправильную работу сервера.

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

Функция add_keys добавляет ключи для шифрования и дешифрования указанному адресу.

И последняя функция add_request добавляет в словарь входящих сообщений сообщение от указанного адреса.

del функции

Эти функции также как и прошлые работают с внутренними данными сервера. Но они, в отличии от прошлых, удаляют данные а не добавляют.

Функция del_user противоположна функции add_user. Она удаляет всё, что связано с указанным адресом с сервером, а также закрывает лог.

Функция del_key удаляет ключи для шифрования и дешифрования указанного адреса.

check функции

Эти функции направлены на получение информации о данных на сервере.

Функция check_request проверяет наличие входящих сообщение от указанного адреса и возвращает его в виде True при наличии или False при отсутствии.

Функции check_address проверяет есть ли указанный адрес среди подключённых пользователей или нет и возвращает True, если он есть или False, если его нет.

get функции

Функция get_free_socket только для внутренней работы сервера и возвращает индекс свободного соккета, если такие есть, иначе ничего.

Функция get_ind_by_address тоже только для внутренней работы, она возвращает номер соккета, к которому подключён данный адрес или ничего, если адрес никуда не подключён.

И последняя функция get_request возвращает первое сообщение от указанного адреса и удаляет его из сервера. Она выкинет ошибку, если сообщений нет вообще.

server control функции

Это основные функции работы сервера, в них заключается логика работы сервера.

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

Функция connect осуществляет подключение к пользователю с указанным адресом и возвращает True при успехе или False при неудаче. Использовать её стоит только внутри сервера.

Функция close_connection закрывает соединение с указанным адресом.

Функция kill_server полностью выключает сервер.

И последняя функция reload_socket, предназначенная для использования внутри самого сервера, перезагружает сокет с указанным индексом.

Другие функции

Функция bool возвращает True, если есть хоть какое-нибудь подключение, или False, если таких нет.

Функция len возвращает количество подключённых к серверу клиентов.

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

А теперь разберём функции на пальцах, тем более здесь ничего сложного нет.

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

Функция save_data сохраняет в файл указанное сообщение.

Статическая функция read_and_return_list не требует объекта класса для использования, но требует для своей работы имя файла из которого будет взята вся информация и возвращена в виде листа.

И последняя функция kill_log записывает в файл время остановки лога и закрывает файл.

Заключение

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

Если есть какие-либо предложения по этому поводу или варианты улучшения кода буду рад почитать в комментариях.

Источник

Познавательно-развлекательный портал