Форум программистов, компьютерный форум, киберфорум
Наши страницы
Python: Сети
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
artem78
3 / 3 / 2
Регистрация: 20.12.2012
Сообщений: 331
1

UDP и TCP сервер

09.02.2018, 02:08. Просмотров 906. Ответов 13

Здравствуйте.
К сети подключено несколько датчиков, которые периодически отправляют UDP пакеты на основной сервер. Сервер сохраняет последнее принятое значение от каждого датчика в переменную и выдаёт их при AJAX-запросе. Web-сервер реализовал через Tornado, а для приёма UDP пакетов использую AsyncUDP из pyserver.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/env python
#coding=utf-8
 
 
from pyserver.network import IUdpCallback, AsyncUDP
 
import tornado.web
import tornado.httpserver
import tornado.ioloop
 
 
#############  Настройки  ############
# Начальные значения датчиков
sensors_values = {
    'Sensor1': 0,
    'Sensor2': 0,
    'Sensor3': 0,
    'Sensor4': 0,
    'Sensor5': 0,
    'Sensor6': 0,
}
 
# Порты
udp_port = 4100
web_port = 8800
######################################
 
 
 
class UDPHandler(IUdpCallback):
 
    def __init__(self):
        pass
 
    # called when new packet arrived
    def on_received(self, server, addr, data):
       global sensors_values
        name, value = data.split(':', 1)
        print('Data recieved:', name, '->', value)
        sensors_values[name] = value
 
 
class WebHandler(tornado.web.RequestHandler):
 
    def get(self):
        self.write(sensors_values)
 
 
if __name__=='__main__':
    # Запуск UDP-сервера
    handler = UDPHandler()
    bind_addr = ''
    udp_server = AsyncUDP(udp_port, handler, bind_addr)
 
 
    # Запуск web-сервера
    app = tornado.web.Application([(r'/', WebHandler)])
 
    server = tornado.httpserver.HTTPServer(app)
    server.bind(web_port)
    server.start(0)
    tornado.ioloop.IOLoop.current().start()
У моего решения обнаруживаются две проблемы:
1) 100% загрузка ядра процессора даже в случае отсутствия приходящих пакетов.
2) AJAX всегда выдаёт начальные значения переменной вместо текущих. Это не просиходит, если включить однопоточный режим работы
Python
1
server.start(1)
, но как сделать, чтобы правильно работало при многопоточном?
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.02.2018, 02:08
Ответы с готовыми решениями:

TCP-Сервер
Здравствуйте. У меня возникла следующая проблема: Есть простой TCP-сервер на...

Udp сокеты
Можно ли как-то гарантировано отправить все данные по udp сокетам? Ну или хотя...

Расшифровка UDP пакета
Добрый день. Возникла одна проблема. Я работаю с лазерным датчиком (LS2D),...

Шифрование UDP сообщений
Доброго времени суток, камрады. Прошу помощи, ибо в шифровании не очень. ...

Scapy отправка Http и UDP пакетов
Вобщем, пришлось столкнуться с Python а вернее со Scapy. Суть проблемы такова :...

13
vic5710
239 / 158 / 103
Регистрация: 10.12.2016
Сообщений: 531
09.02.2018, 12:44 2
pyserver на asyncio, у торнадо свой ioloop. смотри http://www.tornadoweb.org/en/stable/ioloop.html
0
artem78
3 / 3 / 2
Регистрация: 20.12.2012
Сообщений: 331
09.02.2018, 14:18  [ТС] 3
vic5710, И что делать?
0
vic5710
239 / 158 / 103
Регистрация: 10.12.2016
Сообщений: 531
09.02.2018, 14:29 4
или делай на asyncio event_loop все или делай все на tornado ioloop
в ссылке пример
0
artem78
3 / 3 / 2
Регистрация: 20.12.2012
Сообщений: 331
09.02.2018, 14:57  [ТС] 5
vic5710, Там пример для TCP. Как переписать его на UDP?
0
vic5710
239 / 158 / 103
Регистрация: 10.12.2016
Сообщений: 531
09.02.2018, 15:13 6
перепиши сокет
https://stackoverflow.com/questions/...cket-in-python
0
artem78
3 / 3 / 2
Регистрация: 20.12.2012
Сообщений: 331
09.02.2018, 15:24  [ТС] 7
Сделал так, но возникает ошибка.
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def udp_handler(sock, fd, events):
    data = sock.recvfrom(1024)
    print(data)
 
 
if __name__=='__main__':
    # Запуск UDP-сервера
    udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_sock.setblocking(0)
    udp_sock.bind(("", udp_port))
    udp_sock.listen(128)
 
    io_loop = tornado.ioloop.IOLoop.current()
    callback = functools.partial(udp_handler, udp_sock)
    io_loop.add_handler(udp_sock.fileno(), callback, io_loop.READ)
    io_loop.start()
Код
socket.error: [Errno 95] Operation not supported
0
vic5710
239 / 158 / 103
Регистрация: 10.12.2016
Сообщений: 531
09.02.2018, 16:49 8
Цитата Сообщение от artem78 Посмотреть сообщение
udp_sock.listen(128)
udp не надо делать listen, только bind
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#server.py
import socket
import tornado.ioloop
import functools
 
def udp_handler(sock, fd, events):
    data,addr = sock.recvfrom(1024)
    #print(data)
    sock.sendto(data,addr)
 
 
if __name__=='__main__':
    # Запуск UDP-сервера
    udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_sock.setblocking(0)
    udp_sock.bind(("127.0.0.1", 9000))
 
    io_loop = tornado.ioloop.IOLoop.current()
    callback = functools.partial(udp_handler, udp_sock)
    io_loop.add_handler(udp_sock.fileno(), callback, io_loop.READ)
    io_loop.start()
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#client
import time
from socket import *
 
for pings in range(10):
    clientSocket = socket(AF_INET, SOCK_DGRAM)
    clientSocket.settimeout(1)
    message = b'test:';  
    addr = ("127.0.0.1", 9000)
    clientSocket.sendto(message,addr)
    try:
        data, server = clientSocket.recvfrom(1024)
        print(data, pings)
    except Exception as e:
        print(e)
0
artem78
3 / 3 / 2
Регистрация: 20.12.2012
Сообщений: 331
09.02.2018, 17:48  [ТС] 9
vic5710, Так работает, но только если запускать server.start(1). А если поставить больше процессов, то ошибка:
Код
RuntimeError: Cannot run in multiple processes: IOLoop instance has already been initialized. You cannot call IOLoop.instance() before calling start_processes()
0
vic5710
239 / 158 / 103
Регистрация: 10.12.2016
Сообщений: 531
09.02.2018, 23:08 10
Цитата Сообщение от artem78 Посмотреть сообщение
только если запускать server.start(1
где ты у меня это увидел?
0
artem78
3 / 3 / 2
Регистрация: 20.12.2012
Сообщений: 331
09.02.2018, 23:25  [ТС] 11
vic5710, Не у тебя, а у меня. Когда параллельно web-сервер пытаюсь поднять.
0
vic5710
239 / 158 / 103
Регистрация: 10.12.2016
Сообщений: 531
10.02.2018, 13:59 12
Лучший ответ Сообщение было отмечено artem78 как решение

Решение

Цитата Сообщение от artem78 Посмотреть сообщение
RuntimeError: Cannot run in multiple processes: IOLoop instance has already been initialized. You cannot call IOLoop.instance() before calling start_processes()
ЯНДЕКС ПЕРЕВОДЧИК
англ.
RuntimeError: не удается запустить несколько процессов: экземпляр ioloop уже инициализирован. Вы не можете назвать IOLoop.экземпляр () перед вызовом start_processes()
смотри доки tornado

Добавлено через 14 часов 9 минут
у меня получилось так, форкающийся сервер имхо тут излишество
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#server
import socket
import tornado.web
import tornado.ioloop
import functools
 
 # Порты
udp_port = 9000
web_port = 8000
######################################
class D():
    _data = ''    
 
def udp_handler(sock, fd, events):
    data,addr = sock.recvfrom(1024)
    D._data = data
    
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write(D._data)
 
 
if __name__=='__main__':
    # UDP socket
    udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_sock.setblocking(0)
    udp_sock.bind(("", udp_port))
    callback = functools.partial(udp_handler, udp_sock)
    # app start
    app = tornado.web.Application([(
        r'/', MainHandler,
        )]) 
    app.listen(web_port)
    # add UDP callback
    loop = tornado.ioloop.IOLoop.current()
    loop.add_handler(udp_sock.fileno(), callback, loop.READ)
    loop.start()
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#udp sender
from time import localtime,strftime,sleep
from random import randint
import socket
import json
 
 
def set_data():
    d = {}
    d['Today'] = strftime("%Y/%m/%d-%H:%M:%S",localtime())
    for i in range(10):
        d[i] = randint(-100,100)
    return json.dumps(d).encode()
 
 
for pings in range(10):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(1)
    msg = set_data()
    addr = ("", 9000)
    try:
        sock.sendto(msg,addr)
    except Exception as e:
        print(e)
    finally:
        sock.close()    
    sleep(5)
1
artem78
3 / 3 / 2
Регистрация: 20.12.2012
Сообщений: 331
10.02.2018, 15:23  [ТС] 13
vic5710, Спасибо! Только почему для хранения данных используете класс, а не просто переменную? Или без разницы?
0
vic5710
239 / 158 / 103
Регистрация: 10.12.2016
Сообщений: 531
10.02.2018, 15:34 14
для доступности отовсюду. global не применяю

Добавлено через 7 минут
правильней будет
Python
1
2
class D:
    pass
то же что в Си структура
0
10.02.2018, 15:34
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.02.2018, 15:34

TCP клиент asycnio
Добрый день! Пытаюсь реализовать TCP клиент на Python, есть некоторые вопросы....

Создание простейшего TCP servera
Кароче была такая задача. Это решил так. #!/usr/bin/env python import...

Получить данные как по методу UDP Multicast Streams wireshark’а через scapy или pyshark
Добрый день. Снова столкнулся с проблемой при анализе капчи. В wireshark есть...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru