Видео ролики бесплатно онлайн

Смотреть анал видео

Официальный сайт physbook 24/7/365

Смотреть видео бесплатно

wiz 01.02.2011 17:40

PythonВеб-сервер своими руками. Часть 2 — наводим порядок.

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

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

Для начала, применим принцип инкапсуляции и объединим всё барахло сервера и его код в один класс:
1
2
3
4
5
class HTTPServer(object):
def __init__(self, host='', port=8000):
"""Распихиваем по карманам аргументы для старта"""
self.host = host
self.port = port



И заодно допишем к модулю специальный режим, чтобы он мог запускаться как скрипт и делать что-нибудь (условно) полезное:
1
2
3
if __name__ == '__main__':
server = HTTPServer()
server.serve()



Этот код будет выполняться только если модуль будет запущен напрямую (python s02.py) или через специальный режим для запуска модулей, лежащих где-то в недрах библиотеки (python -m s02).

Если(когда) вы столкнётесь с ошибкой «Address already in use» это значит, что ОС ещё не освободила адрес и ждёт завершения каких-то своих операций. Такое бывает если сервер обслуживал подключения, а потом крашнулся. В таком случае надо просто подождать несколько секунд.

Теперь можно втащить сюда и рабочий код сервера.
1
2
3
4
5
6
7
8
9
def serve(self):
"""Цикл ожидания входящих соединений"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((self.host, self.port)) # параметры берём из нашего «контейнера», в который их положили при старте.
sock.listen(50) # количество соединений в очереди, перед тем, как ОС откажется их принимать

while True:
conn, addr = sock.accept() # есть контакт! следующая фаза — разбор чего же там пришло интересного
self.on_connect(conn, addr)



self — обязательный параметр для всех методов класса через который передаётся конкретный его экземпляр.

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

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
def on_connect(self, conn, addr):
"""Соединение установлено, вычитываем запрос"""
data = conn.recv(1024).split('\r\n')
method, url, proto = data<0>.split(' ', 2)

headers = {}
for pos, line in enumerate(data<1:>):
if not line.strip():
break
key, value = line.split(': ', 1)
headers<key.upper> = value

body = '\r\n'.join(data<pos>)
self.on_request(method, url, headers, body, conn)</pos></key.upper>



Всё как и раньше, просто это один из логических участков работы с запросом и потенциально может быть переопределён самыми разными способами. Обратите внимание, что не смотря на то, что self передаётся, туда ничего не складывается — никаких соединений, никаких заголовков и всего такого. Оно просто передаётся следующему «работнику конвейера». Причин тут сразу несколько.
Во-первых, это нарушает принципиальное устройство класса: он называется «сервер», а прицеплять туда детали каждого конкретного соединения получается ни к селу ни к городу.
Во-вторых, сервер у нас один, а соединений много. Если обслуживаются сразу несколько соединений, то они будут постоянно перезаписывать разные участки данных друг друга. Это FAIL.
И, в любом случае, как подсказывает нам практика функционального программирования, чем меньше код создаёт побочных эффектов во время своей работы, тем меньше вероятность возникновения и распространения ошибок.

 1
2
3
4
5
6
7
8
9
10
def on_request(self, method, url, headers, body, conn):
"""Обработка запроса"""
print method, url, repr(body)

conn.send("HTTP/1.0 200 OK\r\n")
conn.send("Server: OwnHands/0.1\r\n")
conn.send("Content-Type: text/plain\r\n")
conn.send("\r\n")
conn.send("Hi there!")
conn.close()



Тут совершенно ничего фантастического пока что нет. Но скоро будет (:

Что же у нас на данный момент получилось? Сервер на любое соединение, на любой запрос без обработки просто по-быстрому отдаёт результат. Интересно, кстати, насколько быстро? Давайте проверим. Воспользуемся утилитой ab из apache-utils:
1
ab -n 5000 'http://localhost:8000/hellow/orld/?whatever=stuff&spam;=eggs'



На нормальном десктопе 5к запросов пролетает за пару секунд даже на таком «медленном» языке, как python. Из отчёта ab нам будут интересны несколько строк:
Requests per second: 4228.88

Смотреть видео онлайн

Онлайн видео бесплатно


Смотреть русское с разговорами видео

Online video HD

Видео скачать на телефон

Русские фильмы бесплатно

Full HD video online

Смотреть видео онлайн

Смотреть HD видео бесплатно

School смотреть онлайн