1
votes

Socket perd la connexion de manière aléatoire

J'ai une socket interrogeant un GPIB Prologixx vers ETH0. J'ai le code pour le faire par des amis. Dans Win 10, le socket obtient un délai d'attente au hasard, parfois l'ordinateur semble fermer la connexion. Je voudrais reconnaître qu'il y a un problème avec la socket pour pouvoir la redémarrer.

Il y a deux messages:

_recv [WinError 10035] Une opération de socket non bloquante n'a pas pu être effectuée immédiatement

Cela ne donne que des résultats invalides et je m'en occupe en vérifiant si les résultats sont raisonnables. C'est aussi seulement temporairement

_send [WinError 10053] Une connexion établie a été interrompue par le logiciel de votre machine hôte

C'est permanent. Les programmes fonctionnent comme avant, meurt juste pas de nouveaux résultats. Tester de nouveaux résultats est difficile, car ils sont à la température et je serai stable pendant un certain temps.

import socket
from numpy import nan
from time import sleep
class PrologixGPIBEthernet:
    PORT = 1234

    def __init__(self, host, timeout=1):
        self.host = host
        self.timeout = timeout

        self.socket = socket.socket(socket.AF_INET,
                                    socket.SOCK_STREAM,
                                    socket.IPPROTO_TCP)
        self.socket.settimeout(self.timeout)

    def connect(self):
        self.socket.connect((self.host, self.PORT))

        self._setup()

    def close(self):
        self.socket.close()

    def select(self, addr):
        self._send('++addr %i' % int(addr))

    def write(self, cmd):
        self._send(cmd)

    def read(self, num_bytes=1024):
        self._send('++read eoi')
        return self._recv(num_bytes)

    def query(self, cmd, buffer_size=1024*1024):
        self.write(cmd)
        return self.read(buffer_size)   

    def _send(self, value):
        encoded_value = ('%s\n' % value).encode('ascii')
        try:
            s = self.socket.send(encoded_value)
        except Exception as e:
            print('_send', e)

    def _recv(self, byte_num):
        try:
            value = self.socket.recv(byte_num).decode('ascii')
        except Exception as e:
            print (',_recv', e)
            value = 'ERROR'
        return value

    def _setup(self):
        # set device to CONTROLLER mode
        self._send('++mode 1')

        # disable read after write
        self._send('++auto 1')

        # set GPIB timeout
#        self._send('++read_tmo_ms %i' % int(self.timeout*1e3))

        # do not require CR or LF appended to GPIB data
#        self._send('++eos 3')


0 commentaires

3 Réponses :


0
votes

Je ne suis pas sûr des messages d'erreur, mais cela ressemble à mon expérience.

Le périphérique prologix est ce que j'appellerais un "interprète" car il ne fonctionne pas de manière transparente avec SCPI.

Par exemple, pour un instrument SCPI normal, je peux demander à l'appareil d'effectuer une mesure, puis je peux demander à lire cette mesure et il me donnera une réponse quand c'est fait. Tant que j'ai un délai d'attente important, il se bloque jusqu'à ce que le tampon soit rempli, puis renvoie le résultat. (Remarque: ce n'est pas ainsi que vous devriez le faire. Utiliser l'interrogation ou une interruption sont de bons moyens d'implémenter des requêtes de périphérique.)

Le périphérique prologix peut être confondu avec le timing. Si j'essaie de copier comment SCPI fonctionnera (comme mentionné ci-dessus) en envoyant une commande pour lire une mesure, mais cette fois, il faut 5 secondes pour effectuer cette mesure et la mettre dans le tampon. Avant que les 5 secondes ne se soient écoulées, je demande au prologix quel est le résultat. Il essaiera de trouver un résultat mais le tampon est vide donc il n'a rien à retourner. Après les 5 secondes, le tampon se remplit mais le prologix ne le sait pas et reste bloqué dans cet état. C'est là que vous obtenez le délai d'expiration de la socket.

La bonne façon de résoudre ce problème consiste à utiliser la fonction d'interrogation dans le prologix pour déterminer quand le tampon a un résultat. Mais ce n'est pas quelque chose que je suis prêt à faire.

Hack 1) Assurez-vous qu'il y a un délai assez grand, mais vous ne savez pas toujours combien de temps vous avez besoin et cela ajoutera beaucoup de retard à votre script.

Hack 2) Forcer délibérément votre script à expirer et réessayer. C'est ce que j'ai implémenté. Je sais que c'est moche, mais c'était un hack rapide qui a fonctionné pendant que j'essayais de déterminer quel était le problème.

def read_timeout_poll(self, repeat):
    # start_time = time.time() # Used if you want to see how long it takes
    mesg = ""
    for _ in range(repeat):
        try:
            sendData = "++read\n"
            self.prolSock.send(sendData.encode())
            mesg = self.prolSock.recv(self.BUFSIZ)
            break
        except socket.timeout:
            time.sleep(1)
        except socket.error as e:
            return "Python Error sending data: " + str(e)
            break
    # print(f"read poll operation took {:.0f} seconds".format(time.time() - start_time)) # This is a guide to see how long it takes to get a result in the buffer
    return mesg 


0 commentaires

0
votes

Cher Zircatron, merci pour votre réponse et vos suggestions. Le délai d'expiration aléatoire n'est pas si problématique, je fais ce que vous suggérez, essayez à nouveau après un certain temps. Mot problématique est la condition quand (le prologixx?) Ferme la connexion. Au final, je devrai rétablir la connexion lorsque le timeout se produit plusieurs fois sans retour fonctionnel. Encore plus moche, mais je suis à court d'idées ...


0 commentaires

0
votes

C'est stupide que nous ne puissions pas commenter la réponse de l'autre dans stackoverflow car nous n'avons pas assez de réputation.

J'ai l'impression de comprendre à moitié le problème. Pour vous aider, quelle séquence les erreurs se produisent-elles et qu'essayez-vous d'envoyer lorsque cela se produit? pouvez-vous donner un exemple du code qui conduit aux erreurs?

Votre commentaire de code dit "# désactiver la lecture après l'écriture" mais vous l'avez activé "self._send ('++ auto 1')". Je le désactiverais. Je trouve que l'activer ne vous permet pas d'avoir le contrôle total de la séquence de commandes.


3 commentaires

Les erreurs se produisent au hasard et je ne lis qu'à partir du port série. Je n'envoie rien.


Désolé, a été trop rapide. Il envoie juste quelques commandes au PROLOGIXX pour le configurer. En raison du caractère aléatoire de l'erreur, un exemple de code n'aiderait pas beaucoup. Comme écrit, je voudrais tregocnize lorsque la connexion a été interrompue. Je peux faire face à des échecs de lecture occasionnels.


Comme pour reconnaître l'abandon par rapport au temps mort? Ne pourriez-vous pas utiliser deux exceptions différentes? comme socket.timeout et socket.error?