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

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

19.07.2019, 10:57. Показов 1913. Ответов 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
Ответ Создать тему
Новые блоги и статьи
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. fontSize": 18, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations":. . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: при выборе сотрудника (справочник Сотрудники) в ТЧ документа. . .
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru