Как я могу получить неблокирующие сокеты connect ()?

Проверьте декодер @property .

10
задан Tom 30 July 2009 в 10:58
поделиться

5 ответов

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

Это можно сделать с помощью класса диспетчера в модуле 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.

5
ответ дан 3 December 2019 в 16:54
поделиться

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

8
ответ дан 3 December 2019 в 16:54
поделиться

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

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

4
ответ дан 3 December 2019 в 16:54
поделиться

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

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

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

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

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

7
ответ дан 3 December 2019 в 16:54
поделиться

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

0
ответ дан 3 December 2019 в 16:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: