Вам также необходимо распараллелить соединения, так как сокеты блокируются, когда вы устанавливаете тайм-аут. В качестве альтернативы вы не можете установить тайм-аут и использовать модуль выбора.
Это можно сделать с помощью класса диспетчера в модуле asyncore . Взгляните на базовый пример http-клиента . Несколько экземпляров этого класса не будут блокировать друг друга при подключении. Вы можете сделать это так же легко, используя потоки, и я думаю, что упрощает отслеживание тайм-аутов сокетов, но, поскольку вы уже используете асинхронные методы, вы также можете оставаться на том же пути.
В качестве примера, следующее работает на всех моих Linux-системах
import asyncore, socket
class client(asyncore.dispatcher):
def __init__(self, host):
self.host = host
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect((host, 22))
def handle_connect(self):
print 'Connected to', self.host
def handle_close(self):
self.close()
def handle_write(self):
self.send('')
def handle_read(self):
print ' ', self.recv(1024)
clients = []
for i in range(50, 100):
clients.append(client('cluster%d' % i))
asyncore.loop()
Где в cluster50 - cluster100 есть множество машин, которые не отвечают или отсутствуют. Сразу начинается печать:
Connected to cluster50
SSH-2.0-OpenSSH_4.3
Connected to cluster51
SSH-2.0-OpenSSH_4.3
Connected to cluster52
SSH-2.0-OpenSSH_4.3
Connected to cluster60
SSH-2.0-OpenSSH_4.3
Connected to cluster61
SSH-2.0-OpenSSH_4.3
...
Это, однако, не принимает во внимание getaddrinfo, которое должно блокироваться. Если у вас возникли проблемы с разрешением DNS-запросов, все должно подождать. Вероятно, вам нужно будет отдельно собрать DNS-запросы и использовать IP-адреса в своем асинхронном цикле
. Если вам нужен более крупный инструментарий, чем asyncore, взгляните на Twisted Matrix . Это немного сложно, но это лучший набор инструментов для сетевого программирования, который вы можете получить для Python.
Используйте модуль выберите
. Это позволяет дождаться завершения ввода-вывода на нескольких неблокирующих сокетах. Вот дополнительная информация о select. Со страницы, на которую есть ссылка:
В C кодирование
select
довольно сложно. В Python это проще простого, но это достаточно близко к версии C что, если вы понимаете, выберите в Python, у тебя не будет проблем с ним в C.
ready_to_read, ready_to_write, in_error = select.select(
potential_readers,
potential_writers,
potential_errs,
timeout)
Вы передаете
выбираете
три списка: первый содержит все сокеты, которые вы можете хочу попробовать читать; второй все розетки, которые вы можете попробовать пишущий, и последний (обычно оставьте пустым) те, которые вы хотите проверить на наличие ошибок. Вы должны отметить, что сокет может входить более чем в один список. Вызовselect
блокируется, но вы можете дать ему тайм-аут. Это вообще разумное дело - дайте ему долгий тайм-аут (скажите минуту), если у вас нет веской причины поступайте иначе.Взамен вы получите три списка. У них есть розетки, фактически читаемый, доступный для записи и в ошибка. Каждый из этих списков представляет собой подмножество (возможно, пустое) соответствующего список, который вы прошли. И если вы поставите сокет в более чем одном списке ввода, он будет только (максимум) на одном выходе list.
Если сокет доступен для чтения список, вы можете быть настолько близко к определенному, насколько мы когда-либо получим в этом бизнесе что
recv
на этом сокете вернет что нибудь. Та же идея для записываемого список. Вы сможетеотправить
что нибудь. Может, не все, что ты хочешь, но что-то лучше, чем ничего. (На самом деле, любой достаточно здоровый сокет вернется как доступный для записи - это просто означает исходящий сетевой буфер место есть.)Если у вас "серверный" сокет, поставьте в списке потенциальных_читателей. Если это появляется в читаемом списке, ваш accept будет (почти наверняка) работать. Если вы создали новый сокет для подключиться к кому-то другому, поместить его в список потенциальных_ писателей. Если это появится в списке для записи у вас есть неплохой шанс, что он подключился.
Используйте twisted .
Это асинхронный сетевой механизм, написанный на Python, поддерживающий множество протоколов, и вы можете добавить свои собственные. Его можно использовать для разработки клиентов и серверов. Он не блокируется при подключении.
К сожалению, нет примера кода, который показывает ошибку, поэтому немного трудно понять, откуда взялся этот блок.
Он делает что-то вроде:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setblocking(0)
s.connect(("www.nonexistingname.org", 80))
Модуль сокета использует getaddrinfo внутренне, что является операцией блокировки, особенно когда имя хоста не существует. Стандартный dns-клиент будет ждать некоторое время, чтобы увидеть, действительно ли имя не существует или задействованы только медленные DNS-серверы.
Решение состоит в том, чтобы подключиться только к IP-адресам или использовать DNS-клиент, который не позволяет -блокирующие запросы, например pydns .
Вы смотрели модуль asyncore ? Возможно, именно то, что вам нужно.