11
votes

Comment puis-je obtenir une prise non bloquante Connect ()?

J'ai un problème assez simple ici. Je dois communiquer avec beaucoup d'hôtes simultanément, mais je n'ai pas besoin de synchronisation car chaque demande est assez suffisante.

À cause de cela, j'ai choisi de travailler avec des prises asynchrones plutôt que de spammer des fils. Maintenant, j'ai un petit problème:

Les trucs ASYNC fonctionne comme un charme, mais lorsque je me connecte à 100 hôtes, et j'obtiens 100 fois-traits (délai d'attente = 10 secondes), puis j'attends 1000 secondes, juste pour savoir que toutes mes connexions ont échoué.

Y a-t-il un moyen d'obtenir également des sockets non bloquants connectés? Ma prise est déjà définie sur NONBLOCKING, mais les appels à la connexion () sont toujours bloqués.

Réduire le délai d'attente n'est pas une solution acceptable.

Je fais cela dans Python, mais je suppose que le langage de programmation n'a pas vraiment d'importance dans ce cas.

Est-ce que j'ai vraiment besoin d'utiliser des threads?


0 commentaires

5 Réponses :


0
votes

Avez-vous regardé le Module ASYNCORE ? Pourrait être exactement ce dont vous avez besoin.


1 commentaires

J'utilise cela, et il bloque toujours sur Connect



8
votes

Utilisez le Sélectionnez Module. Cela vous permet d'attendre l'achèvement d'E / S sur plusieurs prises non bloquantes. Voici Quelques informations supplémentaires sur Select. De la page liée à la page:

in c, codage Sélectionnez est assez complexe. En python, c'est un morceau de gâteau, mais Il est assez proche de la version C que si vous comprenez, sélectionnez dans Python, vous aurez peu de problèmes avec elle en c. xxx

vous passez sélectionnez trois listes: le premier contient toutes les prises que vous pourriez vouloir essayer de lire; le second tout les sockets que vous voudrez peut-être essayer écrire à, et le dernier (normalement laissé vide) ceux que vous voulez Vérifiez les erreurs. Vous devriez noter que Une prise peut aller dans plus d'un liste. L'appel SELECT bloque, mais Vous pouvez lui donner un délai d'attente. C'est généralement une chose sensible à faire - donnez-lui un bon délai d'attente (dire un minute) sauf si vous avez une bonne raison de faire autrement.

En retour, vous obtiendrez trois listes. Ils ont les sockets qui sont en fait lisible, écrit et dans Erreur. Chacune de ces listes est un sous-ensemble (éventuellement vide) du correspondant liste que vous avez passée. Et si vous mettez un socket dans plus d'une liste d'entrée, il ne sera que (au plus) dans une seule sortie liste.

Si une prise est dans la sortie lisible liste, vous pouvez être Aussi proches-à-des-celles-ci-we-wel-get-in-the-business qu'un recv sur cette prise reviendra quelque chose. Même idée pour l'écrite liste. Vous pourrez envoyer quelque chose. Peut-être que tout ce que vous voulez, Mais quelque chose vaut mieux que rien. (En fait, tout raisonnablement en bonne santé la prise reviendra comme une écrite - elle signifie juste que le tampon de réseau sortant l'espace est disponible.)

Si vous avez un socket "serveur", mettez-le dans la liste potentielle_readers. Si ça sort dans la liste lisible, votre accepter sera (presque certainement) travailler. Si vous avez créé une nouvelle prise pour se connecter à quelqu'un d'autre, mettez-le dans le liste potentielle_writers. Si cela apparaît Dans la liste écrite, vous avez un chance décente qu'il ait connecté.


5 commentaires

Il dit spécifiquement qu'il est bloqué sur Connect (). SELECT vous indique seulement ce que lisible ou écritable.


Voir le dernier para de ma réponse. Avec Sélectionnez le multiplexage , vous n'avez pas besoin d'attendre 1000 secondes avant de faire du travail utile. Avec un délai bref, vous pouvez toujours faire du travail utile si tous les points d'extrémité ne sont pas connectés, avec seulement une attente courte. Twisted est bien sûr une alternative, mais comme vous l'avez dit ", il est un peu lourd à entrer".


Ahh, je vois le problème ... Il a défini un délai d'attente, qui signifie que la prise a bloquer.


Je n'ai rien défini explicitement, j'utilisais le module Asyncore de Python, qui semble être plus ou moins une enveloppe autour de Select (). J'ai créé un autre script de test d'exemple courte, crée une prise et la réglage de non bloquant, mais il bloque toujours sur la connexion, tout simplement pas en lecture.


@TOM - Voir, vous n'avez pas mentionné que vous utilisiez Asyncore, avec l'option Timeout, donc ma supposition logique était que vous utilisiez Socket.Settimeout (), qui définit le blocage. Quelle est votre plate-forme et votre version Python - Connect ne bloque pas sur mes systèmes avec SetBlocking (0)



5
votes

Vous devez également parlementer les connexions, car les sockets bloquent lorsque vous définissez un délai d'attente. Vous pouvez également définir un délai d'attente et utiliser le module SELECT.

Vous pouvez le faire avec la classe Dispatcher dans le Module ASYNCORE . Jetez un coup d'œil à la base Exemple de client HTTP . Plusieurs instances de cette classe ne se bloqueront pas sur Connect. Vous pouvez le faire tout aussi facilement à l'aide de threads, et je pense que les délais d'attente de suivi des sockets facilitent, mais que vous utilisez déjà des méthodes asynchrones, vous pouvez aussi bien rester sur la même piste. p>

Par exemple, les travaux suivants sur tous mes systèmes Linux P>

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

...


5 commentaires

Bon, je dois m'excuser ici. J'ai pris le code à partir des docs Python, donc ce n'était donc pas mon code, je l'ai pris pour acquis que c'est correct. Et ça n'a pas fonctionné. Cela m'est arrivé souvent que les gens me donnaient des conseils, qu'ils ne se sont même pas testés eux-mêmes. Je n'aurais jamais pu deviner mon système d'exploitation serait le problème, au lieu du code, alors je pensais que tu es comme un autre gars pensant hes intelligent et copier en coller le code de la documentation sans même vérifier si cela fonctionne. Désolé encore pour ça. J'ai jeté 3 versions complètes aujourd'hui en gaspillant 6 heures, pour trouver que MacOS était le problème.


BTW j'ai testé à nouveau avec un ami sur sa boîte Linux et même gettaddrinfo ne semble pas bloquer là-bas. Nous obtenons une erreur: [errno 115] Opération maintenant en cours. Tellement théoriquement même asynchronisé avec des hôtes non réactifs pouvant fonctionner sous Linux.


@Tom - NP, je suis d'accord qu'il y a des tonnes de réponses non informées ici, en particulier dans les champs non-Windows. Ce qui est pire, c'est que les équipes de non informées finissent par voter mutuellement, ce qui rend difficile de répondre à des réponses correctes.


"Nous obtenons une erreur: [errno 115] Opération maintenant en cours. Donc, théoriquement même asyncore avec des hôtes non réactifs pouvant travailler à Linux" - je suis à peu sûr que ça fait, je ne pouvais tout simplement pas obtenir mon DNS suffisamment cassé pour accrocher afin de le vérifier.


@Jimb, s'il vous plaît donner la réponse au module ASYNCIO?



4
votes

Utilisez torsadé .

Il s'agit d'un moteur de réseautage asynchrone écrit en Python, en soutenant de nombreux protocoles et vous pouvez ajouter le vôtre. Il peut être utilisé pour développer des clients et des serveurs. Il ne bloque pas sur Connect.


2 commentaires

Twisted apporte un tel bonheur. Je travaille avec elle tous les jours et j'essaie de convaincre ceux qui se battent avec une simultanée de rendre leur vie tellement plus facile. Bien sûr, mes collègues ont au moins voir la différence.


J'ai déjà utilisé Twisted, c'est assez agréable, mais la documentation est aussi tordue. En outre, il sera difficile d'intégrer ma source à cela. Êtes-vous certain que cela ne bloque pas sur Connects? Pourrait essayer d'aller pour cela alors.



7
votes

Malheureusement, il n'y a pas d'exemple de code qui montre le bogue, il est donc un peu difficile de voir où provient ce bloc.

Il fait quelque chose comme: P>

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


3 commentaires

Cela coupe à peu près au cœur du problème. Semble avoir des problèmes DNS. Le comportement de mon application (au moins dans le stade initial) est assez similaire à un PortScanner: Je dépend des résultats très rapides, que le Connect fonctionne ou non. Utilisation de gettaddrinfo sur des blocs de nom d'hôte inexistants également pour des prises non bloquantes, ce qui est mauvais (pour moi). Je pourrais également vous connecter à beaucoup d'hôtes inexistants et je ne peux pas vous permettre d'attendre 10 secondes sur chaque hôte inexistant.


Mon but était très différent, mais a été corrigé en changeant la commande. c'est-à-dire d'abord connecter alors ensemble d'entretien.


@Ben qui a réparé mon problème aussi! Merci!