Asyncio закрыть соединение оставить соединение в состоянии TIME_WAIT - PullRequest
1 голос
/ 08 марта 2019

Привет! У меня есть скрипт, который сохранял состояние порта моего устройства, это упрощенная версия.

Когда соединение установлено (устройство существует), тогда я закрываю соединение, состояние соединения становится TIME_WAIT.Вовремя, когда это соединение заполняется и достигает максимального значения, разрешенного ОС (если я помню)как ssh, vnc и т. д.

Я запускаю сценарий на Ubuntu 18.04 с python 3.5.6

import asyncio
import ipaddress
import sys

async def check_port(ip, port, timeout=1):
    conn = None
    response = False
    writer = None

    try:
        conn = asyncio.open_connection(ip, port)
        reader, writer = await asyncio.wait_for(conn, timeout=timeout)
        response = True
    except asyncio.CancelledError:
        print("asyncio cancel")
    except:
        response = False
    finally:
        if writer is not None:
            writer.close()
        if conn is not None:
            conn.close()
        print("Closing connection {}:{}".format(ip, port))

    print("{}:{} {}".format(ip, port, response))

async def poll_status():
    ips = [str(ip) for ip in ipaddress.IPv4Network("192.168.1.0/24")]
    while True:
        try:
            tasks = [check_port(ip, 53) for ip in ips]
            await asyncio.wait(tasks)
        except asyncio.CancelledError:
            break
        except KeyboardInterrupt:
            break
        except:
            pass
        await asyncio.sleep(1)

async def shutdown(task):
    task.cancel()
    await task
    await asyncio.sleep(1)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    task = asyncio.ensure_future(poll_status())
    try:
        loop.run_forever()
    except:
        pass
    finally:
        loop.run_until_complete(asyncio.wait([shutdown(task)]))
        loop.close()

Соединение продолжало накапливаться так (вывод из "netstat -nput | grep TIME_WAIT"") 192.168.1.1 - мой роутер, поэтому он успешно проверил порт, но оставил много закрытых соединений.Удаление соединения заняло много времени

tcp        0      0 192.168.1.4:42102       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:42582       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:46560       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:39428       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:45806       192.168.1.1:53          TIME_WAIT   -                                     
tcp        0      0 192.168.1.4:44752       192.168.1.1:53          TIME_WAIT   -                                      
tcp        0      0 192.168.1.4:40726       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:49864       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:38812       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:48464       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:41372       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:43408       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:47360       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:45478       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:41904       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:40160       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:46196       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:48744       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:49554       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:47774       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:39370       192.168.1.1:53          TIME_WAIT   -                                    
tcp        0      0 192.168.1.4:43994       192.168.1.1:53          TIME_WAIT   - 

1 Ответ

0 голосов
/ 08 марта 2019

Я не разбираюсь в сетевых вещах, не уверен, поможет ли этот ответ, но вот мои два цента.

Первое о выводе netstat.Это связанный маршрутизатор и, похоже, не связанный с вашими ограничениями ОС.Быстрый поиск в Google показывает следующее:

TIME_WAIT указывает, что локальная конечная точка (эта сторона) закрыла соединение.Соединение поддерживается так, что любые задержанные пакеты могут быть сопоставлены с соединением и обработаны соответствующим образом.Соединения будут удалены, когда они истекают в течение четырех минут.

Кажется, что ваш код закрыл соединение, т.е. делает все правильно.

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


Давайте теперь рассмотрим ваш код.


То, что вы делаете в строке asyncio.wait(tasks), параллельно выполняет все ваши проверки.В зависимости от количества ips это может быть слишком много.С большой вероятностью вы можете воспользоваться asyncio.Semaphore для ограничения максимального количества параллельных проверок.Это будет выглядеть следующим образом:

sem = asyncio.Semaphore(100)

async def check_port(ip, port, timeout=1):
    async with sem:
        # main code here

Вы также можете прочитать этот ответ , чтобы увидеть реальный пример использования семафора.


Следующие вещи, которые могут вам понадобитьсяисправить это так: CancelledError:

except asyncio.CancelledError:
    print("asyncio cancel")

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


except:
    response = False

Вы никогда не делаете этого.Пожалуйста, прочитайте эту тему для получения подробной информации.

Вместо этого вы должны хотя бы сделать что-то вроде следующего:

except Exception as exc:    # catch Exception or it's subclasses only
    logging.exception(exc)  # log for purpose not to miss exception you can fix
    response = False
...