Вопрос

У меня здесь довольно простая проблема. Мне нужно общаться с большим количеством хостов одновременно, но мне не нужна синхронизация, потому что каждый запрос самодостаточен.

Из-за этого я решил работать с асинхронными сокетами, а не со спам-потоками. Теперь у меня есть небольшая проблема:

Асинхронная работа работает как чудо, но когда я подключаюсь к 100 хостам и получаю 100 тайм-аутов (тайм-аут = 10 секунд), то я жду 1000 секунд, просто чтобы выяснить, все ли мои соединения потерпели неудачу.

Есть ли способ также получить неблокирующие соединения сокетов? Мой сокет уже настроен на неблокирование, но вызовы connect () все еще блокируются.

Сокращение времени ожидания не является приемлемым решением.

Я делаю это на Python, но, полагаю, язык программирования в данном случае не имеет значения.

Мне действительно нужно использовать темы?

Это было полезно?

Решение

Вам также необходимо распараллелить соединения, так как сокеты блокируются, когда вы устанавливаете время ожидания. Кроме того, вы не можете установить время ожидания и использовать модуль выбора.

Это можно сделать с помощью класса диспетчера в 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 три списка: первый   содержит все сокеты, которые вы могли бы   хочу попробовать читать; второе все   розетки, которые вы можете попробовать   пишу, и последнее (обычно   оставлено пустым) те, которые вы хотите   проверить на ошибки. Вы должны отметить, что   сокет может входить в несколько   список. Вызов select блокируется, но   Вы можете дать ему тайм-аут. Это   как правило, разумная вещь, чтобы сделать -   дать ему хороший длительный перерыв (скажем,   минут), если у вас нет веских причин   поступай иначе.

     

В ответ вы получите три списка.   У них есть розетки, которые   на самом деле читаемый, записываемый и в   ошибка. Каждый из этих списков является подмножеством   (возможно, пустой) соответствующего   список, который вы передали. И если вы положите   сокет в более чем одном входном списке, это   будет только (максимум) в одном выводе   список.

     

Если сокет находится на выходе для чтения   список, вы можете быть   а-близко к уверены-как-мы-все получить в этом-бизнеса   что recv в этом сокете вернет   что-то. Та же идея для записи   список. Вы сможете отправить   что-то. Может быть, не все, что вы хотите,   но что-то лучше, чем ничего.   (На самом деле, любой достаточно здоровый   сокет вернется как записываемый - это   просто означает исходящий сетевой буфер   место доступно.)

     

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

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

Он делает что-то вроде:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setblocking(0)
s.connect(("www.nonexistingname.org", 80))

Модуль сокетов использует getaddrinfo для внутренних целей, что является блокирующей операцией, особенно когда имя хоста не существует. Стандартный совместимый DNS-клиент подождет некоторое время, чтобы выяснить, действительно ли имя не существует или в нем задействованы только некоторые медленные DNS-серверы.

Решение состоит в том, чтобы подключиться только к IP-адресам или использовать DNS-клиент, который разрешает неблокирующие запросы, например pydns .

Используйте витой .

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

Вы смотрели на модуль asyncore ? Может быть именно то, что вам нужно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top