Скрыть объявление
На нашем форуме недоступен просмотр изображений для неавторизованных пользователей. Если Вы уже зарегистрированы на нашем форуме, то можете войти. Если у Вас еще нет аккаунта, мы будем рады, если Вы к нам присоединитесь. Зарегистрироваться Вы можете здесь.

Micropython HTTP сервер

Тема в разделе "MicroPython", создана пользователем evgeny2k, 15 авг 2016.

  1. evgeny2k

    evgeny2k Новичок

    Сообщения:
    18
    Симпатии:
    3
    Всем привет. Хочу поделиться с сообществом своей наработкой, а именно модулем HTTPServer. Сервер работает в блокирующем режиме, но для себя использовал и неблокирующую версию. При написании сервера использовал вот эту статью:
    https://andreymal.org/socket3
    Рекомендую почитать для полного понимания.
    Во вложении файл сервера и пример использования. Также дублирую пример здесь. Сервер работает только с get-запросами, но принимает и параметры. Предложения по доработке и добрая критика приветствуются.
    Пример использования (раскрыть)

    Код (Text):
    1. # -*- coding: utf-8 -*-
    2.  
    3. from HTTPServer import Server
    4. from machine import Pin
    5. import gc
    6.  
    7. led = Pin(2, Pin.OUT) # Присваиваем переменной led GPIO2 и назначаем его выходом
    8. led.high() # Переводим порт в состояние 1
    9.  
    10. def test1(path): # Пример функции, принимающей только параметр path..
    11.     print('this is func test1 with path='+path)
    12.     return 'this is func test1 with path='+path
    13.  
    14. def test2(path,params): # Эта фуекция принимает на вход path и params, где params имеет вид словаря вида {'param_name':'param_value'}
    15.     print('this is func test2 with path='+path+' and params='+str(params))
    16.     return 'this is func test2 with path='+path+' and params='+str(params)
    17.  
    18. def stop(): # Пример ф-ии без входных параметров. Остановка сервера.
    19.     test.stop = True
    20.     return 'stoped'
    21.  
    22. def free(): # Пример ф-ии без параметров. Показывает в браузере состояние памяти.
    23.     result = "mem free:"+str(gc.mem_free())+" mem allocated:"+str(gc.mem_alloc())
    24.     return result
    25.  
    26. def switch(): # Ф-ия без параметров. Просто переключает состояние светодиода на ESP
    27.     led.value(not led.value())
    28.     return 'Pin 2 status '+str(led.value())
    29.  
    30. test = Server(8266) # Создаём объект сервера с указанием номера порта. По умолчанию используется порт 8080
    31. test.RouteAdd('/test1', test1) # Добавляем обрабатывающую ф-ию test1 для маршрута /test1
    32. test.RouteAdd('/test2', test2) # Так поступаем и для остальных маршрутов и их функций
    33. test.RouteAdd('/stop', stop)
    34. test.RouteAdd('/free', free)
    35. test.RouteAdd('/switch', switch)
    36. test.Run() # Запускаем сервер
    37.  


    upd:
    Что-то архив не могу залить. Даю листинг здесь.
    HTTPServer.py (раскрыть)

    Код (Text):
    1.  
    2. # -*- coding: utf-8 -*-
    3. import socket
    4.  
    5. class Server:
    6.     def send_answer(self, conn, status="200 OK", typ="text/plain; charset=utf-8", data=""):
    7.         data = data.encode("utf-8")
    8.         conn.send(b"HTTP/1.1 " + status.encode("utf-8") + b"\r\n")
    9.         conn.send(b"Server: simplehttp\r\n")
    10.         conn.send(b"Connection: close\r\n")
    11.         conn.send(b"Content-Type: " + typ.encode("utf-8") + b"\r\n")
    12.         conn.send(b"Content-Length: " + bytes(len(data)) + b"\r\n")
    13.         conn.send(b"\r\n")# после пустой строки в HTTP начинаются данные
    14.         conn.send(data)
    15.  
    16.     def RouteAdd(self, path, funcname):
    17.         if path not in self.routes:
    18.             self.routes[path] = funcname
    19.  
    20.     def parse(self, conn, addr):# обработка соединения в отдельной функции
    21.         data = b""
    22.         while not b"\r\n" in data: # ждём первую строку
    23.             tmp = conn.recv(1024)
    24.             if not tmp: # сокет закрыли, пустой объект
    25.                 break
    26.             else:
    27.                 data += tmp
    28.  
    29.             if not data: # данные не пришли
    30.                 return # не обрабатываем
    31.  
    32.             udata = data.decode("utf-8")
    33.             # берём только первую строку
    34.             udata = udata.split("\r\n", 1)[0]
    35.             # разбиваем по пробелам нашу строку
    36.             method, string, protocol = udata.split(" ", 2)
    37.             if string.find('?') != -1:
    38.                 address = string.split('?')[0]
    39.                 params = dict(b.split('=') for b in string.split('?')[1].split('&'))
    40.             else:
    41.                 address = string
    42.                 params = {}
    43.             if method != "GET":
    44.                 self.send_answer(conn, "404 Not Found", data="Page not found")
    45.                 return
    46.             if address in self.routes:
    47.                 if len(params) > 0:
    48.                     self.send_answer(conn, typ="text/html; charset=utf-8", data=self.routes[address](address, params))
    49.                 else:
    50.                     try:
    51.                         self.send_answer(conn, typ="text/html; charset=utf-8", data=self.routes[address]())
    52.                     except:
    53.                         self.send_answer(conn, typ="text/html; charset=utf-8", data=self.routes[address](address))
    54.                 return
    55.  
    56.             else:
    57.                 self.send_answer(conn, "404 Not Found", data="Page not found")
    58.                 return
    59.  
    60.     def __init__(self,port=8080):
    61.         self.routes = {}
    62.         self.stop = False
    63.         self.sock = socket.socket()
    64.         self.sock.bind( ("", port) )
    65.         self.sock.settimeout(2)
    66.         self.sock.listen(5)
    67.  
    68.     def Run(self):
    69.         try:
    70.             while 1: # работаем постоянно
    71.                 try:
    72.                     if self.stop: break
    73.                     conn, addr = self.sock.accept()
    74.                     #print("New connection from " + addr[0])
    75.                 except:
    76.                     continue
    77.                 try:
    78.                     self.parse(conn, addr)
    79.                 except:
    80.                     self.send_answer(conn, "500 Internal Server Error", data="Error")
    81.                 finally:
    82.                 # так при любой ошибке
    83.                 # сокет закроем корректно
    84.                     conn.close()
    85.         finally:
    86.             self.sock.close()
    87.             # так при возникновении любой ошибки сокет
    88.             # всегда закроется корректно и будет всё хорошо
     
    Последнее редактирование: 15 авг 2016
    teriva и Nick5708 нравится это.
  2. straga

    straga Новичок

    Сообщения:
    1
    Симпатии:
    0
    А сколько RAM памяти он потребляет на ESP?

    А можно не блокирующую версию посмотреть тоже.
     
    Последнее редактирование: 20 сен 2016
  3. UR5SIX

    UR5SIX Новичок

    Сообщения:
    3
    Симпатии:
    0
    Тоже интересует неблокирующая версия
     
  4. corpse

    corpse Новичок

    Сообщения:
    23
    Симпатии:
    1
    Добрый день! А как быть с передачей параметров? Не могу разобраться. :(
    test.RouteAdd('/test2', test2) - здесь мы передаём в качестве второго параметра метод. Но если мне нужно будет в этом методе добавить обработку хэдеров, урла?
     
  5. Cosmatos

    Cosmatos Новичок

    Сообщения:
    2
    Симпатии:
    0
    при попытке импорта выдает ошибку. Говорит не знает такого модуля.
    ImportError: no module named 'HTTPServer'
     
  6. __ab__

    __ab__ Новичок

    Сообщения:
    21
    Симпатии:
    2
    если использовать select, можно написать очень простой вариант сервера, который не будет особо мешать выполнению чего-то еще:
    Код (Text):
    1. import socket,select
    2.  
    3. def handle_http(client, client_addr):
    4.     client.send("HTTP/1.0 200 OK\r\n\r\nHelloWorld!!!\r\n  %s" % str(client_addr))
    5.     client.close()
    6.  
    7. def serv(port=80):
    8.     http = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    9.     addr = (socket.getaddrinfo("0.0.0.0", port))[0][-1]
    10.     http.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    11.     http.bind(addr)
    12.     http.listen(4)
    13.  
    14.     while True:
    15.         r, w, err = select.select((http,), (), (), 1)
    16.         if r:
    17.             for readable in r:
    18.                 client, client_addr = http.accept()
    19.                 handle_http(client, client_addr)
    20.     # a cюда можно вставить обработку еще-чего-то
    21.     # а можно вставить такую обработку по таймеру
    22.  
    23. serv()
     
    Последнее редактирование: 4 окт 2018

Поделиться этой страницей