Конкретно по поводу цикла с sleep может прокатить даже просто вместо обычного sleep использовать asyncio.sleep, потому что в процессе его выполнения asyncio поднимет любую другую задачу, по которой есть события, и если во всех задачах такое есть, то между ними будет происходить переключение как минимум по каждому asyncio.sleep. Но в целом нужно понимать, что асинхронный подход требует кардинального пересмотра архитектуры.
korsar182, делаются два туннеля через разных провайдеров на один сервер в интернетах. Далее делается один роут с двумя шлюзами:
ip route add default nexthop via шлюз1 weight 1 nexthop via шлюз2 weight 1
На той стороне аналогичной магией заворачиваем трафик до нашей домашней сетки в два туннеля.
Остаётся одна проблема - чтобы трафик роутился не не по одному выбранному при первичной маршрутизации маршруту, а для каждого пакета. В своё время для этого приходилось патчить ядро на обоих концах туннеля. Есть ли сейчас более нормальные механизмы - я не интересовался. Но если автору надо торренты, то эта магия ему может быть и не нужна. Достаточно того, чтобы было достаточное количество коннектов, раскиданных по разным туннелям.
poisons, это ещё надо правильно настроить, чтобы роутился через 2 VPN с равными весами. И на том конце нужен канал 200+ Мбит/с в обе стороны, чтобы всё прокачать.
zeuss56, это ни фига не простая замена, особенно для C++ с его перегрузкой функций, сложной системой типов, константными и неконстантными доступами и всё такое.
И что касается заголовков - вот маленькая демонстрация:
725 строк после препроцессинга в программе, в которую включен всего один не самый сложный заголовочный файл. А что бывает в сложных проектах с десятками подключаемых заголовочных файлов, содержащих сложные структуры данных и множество функций? Даже прекомпиляция заголовков не исключает необходимости всё это перебирать для проверки того, какие идентификаторы что означают в компилируемом коде.
(Правда, справедливости ради, осмысленных строк после выкидывания мусора остаётся 266)
RFC793 предполагает, что данные о коннектах хранят сами хосты, в нём непосредственно участвующие, вся промежуточная инфраструктура не несёт от этого никаких дополнительных расходов, только роутит пакетики. Любые инициативы по долгой жизни, закрытию коннектов по таймаутам и всё такое - это их собственные трудности, которые никак не влияют на магистральное оборудование.
Однако в случае с stateful nat по дороге всё совсем не так. Каждый коннект - это нагрузка на маршрутизаторы. А если, например, оба хоста просто помрут без прежупреждения, вечно хранить их коннекты, что ли? Помимо того, что nat-таблицы всегда будут пухнуть, в такой ситуации возможна очень простая атака на маршрутизаторы с nat путём открытия множества незакрываемых коннектов к случайным сайтам.
Поэтому требование использовать keepalive закономерно и полностью законно. Если не нравится, то всегда можно перейти stateless tcp без nat с личным выделенным IP.
До кучи есть множество других нюансов. Например, при использовании SO_LINGER_TIME=0 при закрытии коннекта посылается не FIN, а RST, а практика показывает, что некоторые несознательные админы RST-пакеты тупо режут, пытаясь так решать некоторые свои проблемы. В итоге пользователи с опцией SO_LINGER_TIME=0 могут создавать висящие коннекты совершенно неосознанно.
Тут функция запустится 10 раз с рандомными параметрами, а потом мы дождёмся завершения всех 10 и получим их результаты.