Форум программистов, компьютерный форум, киберфорум
Python
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
1303 / 843 / 409
Регистрация: 12.03.2018
Сообщений: 2,305

Повторное подключение сокета вызывает некорректное поведение веб-сервера

19.07.2019, 10:57. Показов 1876. Ответов 0

Студворк — интернет-сервис помощи студентам
Есть два py скрипта (python 2.7), которые запускаются на linux машине (.service):

1) Процесс П, который обрабатывает некие данные (запускается в GUI).

2) Сервер Flask. Позволяет клиенту через запросы получить актуальные данные из П и внести изменения.

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

Два процесса могут быть запущены независимо друг от друга, т.е сначала может быть запущен П, а затем уже сервер, или наоборот. Объединить два процесса в один нельзя. Из-за отсутствия последовательности запуска необходимо организовать "динамическое" соединение через сокет. Т.е., если П активен, а сервер запускается, то сервер подключается к сокету, открытому на П. Иначе, если П запускается, а сервер уже работает, то сервер будет пытаться подключиться к сокету П, пока ему это не удастся сделать (пока нет соединения с сокетом, сервер на любой из запросов будет возвращать статус 500).

Основные части кода

Процесс П включает в себя два метода (вызываются по кнопке в GUI):

process_start запускаются при запуске процесса;

process_stop запускается при остановке процесса.

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
63
64
65
66
67
68
69
70
71
72
73
74
from threading import Thread
import socket
import pickle
from datetime import datetime
 
def process_start():
    global working
    working = True
 
    global SocketThread
    SocketThread = Thread(target=SocketThreadProc)
    # SocketThread.daemon = True
    SocketThread.start()
 
def process_stop():
    global working
    working = False
 
    sock.close()
    SocketThread.join()
 
def SocketThreadProc():
    global sock
 
    sock = socket.socket()
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('localhost', 9090))
    sock.listen(1)
 
    global conn
 
    while working:
        try:
            sock.settimeout(1)
            conn, addr = sock.accept()
            conn.setblocking(1)
            decoder = PacketDecoder()
 
            now = str(datetime.now())
            print "{}: {} connected.".format(now, ":".join(map(str, addr)))
 
            try:
                while working:
                    data = conn.recv(1024)
                    data = bytearray(data)
                    decoder.feed(data)
                    for packet in decoder.decode():
                        process_packet(packet)  #
            except Exception as err:
                print 'Sub try error:', err
            finally:
                conn.close()
                now = str(datetime.now())
                print "{}: {} closed.".format(now, ":".join(map(str, addr)))
        except socket.timeout as err:
            print err
            pass
        except socket.error as err:
            print err
            break
 
def process_packet(packet):
    _, set_method, _ = PacketDecoder.parse_header(packet[:8])
    data = pickle.loads(packet[8:])
 
    if not set_method:
        # GET
        # разбор пакета, формирование пакета для ответа
        ...
        conn.send(resp_packet)  # отправка пакета серверу
    else:
        # SET
        # разбор пакета, внесение изменений в данные процесса П
        ...
Сервер Flask

Два метода:

get вызывается каждые 2 сек (интервал задается). Формирует пакет, отправляет в сокет, получает ответ от процесса П и возвращает результат клиенту.

set вызывается при взаимодействии пользователя с формой (например, кнопка). Формирует пакет, отправляет серверу. Клиенту возвращает 200, если все хорошо.

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
63
64
65
66
67
68
69
70
71
72
@app.route('/get-data', methods=['POST'])
def get():
    global sock_connected
 
    if not sock_connected:
        socket_connection()
        return Response({'success': False}, 500, {'ContentType': 'application/json'})
 
    # формирование пакета package
    ...
    try:
        sock.send(package)
 
        # прием ответа от процесса П
        data = bytearray(sock.recv(1024))
        llength = list(data[:3])
        length = (llength[0] << 16) | (llength[1] << 8) | llength[2]
        data = data[3:]
        while len(data) != length:
            data += bytearray(sock.recv(1024))
        data = pickle.loads(data)
 
        res = dict()
        for d in data["data"]:
            res[d['name']] = d['value']
        return json.dumps(res)
    except socket.error:
        # [10053] errno.WSAECONNABORTED стандартная ошибки
        sock.close()
        sock_connected = False
        return Response({'success': False}, 500, {'ContentType': 'application/json'})
 
 
@app.route('/set-data', methods=['POST'])
def set():
    global sock_connected
 
    if not sock_connected:
        socket_connection()
        return Response({'success': False}, 500, {'ContentType': 'application/json'})
 
    # формирование пакета package
    ...
    try:
        sock.send(package)
        return Response({'success': True}, 200, {'ContentType': 'application/json'})
    except socket.error:
        # [10053] errno.WSAECONNABORTED стандартная ошибки
        sock.close()
        sock_connected = False
        return Response({'success': False}, 500, {'ContentType': 'application/json'})
 
 
def socket_connection():
    global sock
    global sock_connected
    sock_connected = False
 
    sock = socket.socket()
    try:
        sock.connect(('localhost', 9090))
        sock_connected = True
    except socket.error as error:
        if error.errno == errno.ECONNREFUSED:
            print('Error: ECONNREFUSED')
        else:
            print(error)
    print 'STATUS SOCKET CONNECTED:', sock_connected
 
if __name__ == '__main__':
    socket_connection()
    app.run(host='0.0.0.0')
Если изначально запущен сервер, и я запускаю/останавливаю процесс П, то все отлично, если П отключен, сервер возвращает код 500, как только П запускается, статус 200.

Если изначально запущен процесс П, то при запуске сервера все тоже отлично.

Проблема возникает тогда, когда запущен процесс П, и я насколько раз запускаю/останавливаю сервер (выше я указал, что первый запуск проблем не вызывает). Не смотря на то, что серверу удается подключиться к сокету процесса П (это видно в логах: функция socket_connection выдает STATUS SOCKET CONNECTED: True), сервер работает некорректно: вызов get-data (каждые 2 сек) происходит, но не обрабатывается. В логах Flask не отображается, что пришел запрос get-data. В отладчике хрома (F12 - Network) все запросы get-data красные, а статус - "canceled".

А вот если кликнуть на кнопку, то set-data нормально обрабатывается сервером. В логах Flask есть. Статус - 200.

Подскажите, пожалуйста, в чем может быть проблема.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
19.07.2019, 10:57
Ответы с готовыми решениями:

Повторное использование сокета
Добрый день пишу асинхронный клиент и столкнулся с проблемой повторного соединения с сервером. повторном вызове метода Connect ничего не...

Повторное использование сокета winsock
Здравствуйте. Мне нужно написать FTP клиент с обязательным использованием winsock api. За последнее время перечитал много разнообразных...

Boost asio повторное открытие сокета
Добрый день. Такая проблема, что открываю сокет после запуска, и все идеально: принимаю ,большое количество пакетов и те, которые...

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
19.07.2019, 10:57
Помогаю со студенческими работами здесь

Повторное создание JVM после ее уничтожения вызывает внутри функции бесконечный цикл исключений ???
Повторное создание JVM после ее уничтожения вызывает внутри функции бесконечный цикл исключений ??? Даже при динамической загрузке...

Classic Bluetooth странное поведение сокета
Доброго времени суток ! Пытаюсь подружить устройство на stm32+CH-06 с компом Использую Embarcadero® C++Builder XE8 Version...

Некорректное поведение клавиатуры
Поставил Mint 17.3, первые пару дней всё работало нормально, затем с клавиатурой произошла ерунда; 1.ScrollLock постоянно включен; ...

Некорректное поведение edittext
Я использую ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); String pasteData; ...

Некорректное поведение GetClientRect
Есть MDI приложение. Запущено на машине с 2мя мониторами. На втором - маленькое разрешение(1024x768). Когда открывается окошко, там...


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

Или воспользуйтесь поиском по форуму:
1
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Программа принимает математическое выражение в виде строки и выдаёт его производную в виде строки и вычисляет значение производной при заданном х Логарифм записывается как: (x-2)log(x^2+2) -. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru