jjacques68 Posté(e) le 7 mars 2020 Signaler Posté(e) le 7 mars 2020 (modifié) Bonjour à tous, Pour ceux qui ont commencé à jouer avec la HC3, j'ai une petite question : J'ai un QA qui envoie des trames sur une socket TCP vers un serveur. ça marche avec ce code (je vois mes trames arriver sur le serveur) : function QuickApp:onInit() self:debug("onInit") self:Open_Socket() end function QuickApp:Open_Socket() self.ip = self:getVariable("IP") self.port = tonumber(self:getVariable("Port")) self.sock = net.TCPSocket() self.sock:connect(self.ip, self.port) end function QuickApp:Send(MaTrame) --affiche la trame dans le label self:updateView("LBL_Buffer", "text", tostring(MaTrame)) --envoi la trame self.sock:write(MaTrame, { success = function() self:debug("data sent") end, error = function(err) self:debug("error while sending data") self.sock:close() fibaro.sleep(200) self:Open_Socket() fibaro.sleep(200) self:Send(MaTrame) end }) end Donc en gros, J'ouvre la socket au démarrage du QA, et j'envoi la trame sur appel de la méthode Send(MaTrame) Actuellement je passe par un bouton dans le QA pour déclencher l'envoi, plus tard ce sera fait par scène, bref... le problème est pas là. Le soucis est que si le serveur TCP redémarre, je n'arrive plus à relancer la connexion depuis le QA ! malgré ces lignes : self.sock:close() fibaro.sleep(200) self:Open_Socket() fibaro.sleep(200) self:Send(MaTrame) où je ferme la précédente socket, je la ré-ouvre, et je renvoi la trame (le tout temporisé) ! Et bien au premier essai, après redémarrage du serveur TCP, il me répond que la trame a bien été envoyé. Et biensûr j'ai rien vu arriver sur le serveur. Au deuxième essai il boucle indéfiniment en me disant "error while sending data". Comment peut-on réinitialiser la socket proprement, et relancer la trame qui n'a pas pu être envoyée !! des idées ???? merciiiiiiiiiiiiii ! Modifié le 7 mars 2020 par jjacques68
Krikroff Posté(e) le 7 mars 2020 Signaler Posté(e) le 7 mars 2020 Quelques remarques: 1. Il faut placer de préférence l’instanciation du socket dans le onInit ainsi que le nécessaire pour la configuration / paramétrage soit function QuickApp:onInit() self.sock = net.TCPSocket() self.ip = self:getVariable("IP") self.port = tonumber(self:getVariable("Port")) end 2. Ajouter une méthode Close_Socket() dans le QuickApp function QuickApp:Close_Socket() self.sock:close() end 3. La méthode Open_Socket ne devrait servir qu'a l'ouverture du socket + trace etc... function QuickApp:Open_Socket() self:debug("open socket") self.sock:connect(self.ip, self.port) end 4. Utiliser de préférence setTimeout (non bloquant) à la place de fibaro.sleep(xxx) car net.TCPSocket est asynchrone... soit remplacer les lignes self.sock:close() fibaro.sleep(200) self:Open_Socket() fibaro.sleep(200) self:Send(MaTrame) PAR self.Close_Socket() -- socket closed fibaro.setTimeout(5000, function() self:Open_Socket() self:Send(MaTrame) end) -- re-connection attempt (every 5s) 5. Ne pas hésiter à restituer le message d'erreur retourné comme ceci self:debug("connection error:", message) Je n'ai rien testé mais cela permettra de mieux identifier par la suite les points bloquants 1
jjacques68 Posté(e) le 7 mars 2020 Auteur Signaler Posté(e) le 7 mars 2020 J'ai fais comme tu dis : function QuickApp:onInit() self.sock = net.TCPSocket() self.ip = self:getVariable("IP") self.port = tonumber(self:getVariable("Port")) self:Open_Socket() end function QuickApp:Open_Socket() self.sock:connect(self.ip, self.port) self:debug("Socket open") end function QuickApp:Close_Socket() self.sock.close() self:debug("Socket close") end function QuickApp:Send(MaTrame) --affiche la trame dans le label self:updateView("LBL_Buffer", "text", tostring(MaTrame)) --envoi la trame self.sock:write(MaTrame, { success = function() self:debug("data sent") end, error = function(err) self:debug("error : "..err) self:Close_Socket() fibaro.setTimeout(5000, function() self:Open_Socket() self:Send(MaTRame) end) end }) end Le comportement est vraiment étrange : - tout est toujours ok au démarrage du QA. - mais après redémarrage du serveur TCP, pareil la 1ère trame envoyée me répond "data sent", mais je vois toujours rien ! - à la 2ème trame, j'ai l'erreur "Broken Pipe" (logique je comprends...) - et le setTimeout semble prendre après très très longtemps (plus que les 5 secondes) : j'ai le "Socket Open" qui arrive après 10 s !! - et la trame n'a pas été renvoyée étrange tout ça
Krikroff Posté(e) le 7 mars 2020 Signaler Posté(e) le 7 mars 2020 Hum le socket doit mal gérer la déconnection. Tu as essayer sans faire le close ? Juste rejouer le send toutes les 5 secondes jusqu’à livraison.Si le QA plante il faudrait penser à faire le sens dans un pcall pour protéger le qa du plantage.
jjacques68 Posté(e) le 8 mars 2020 Auteur Signaler Posté(e) le 8 mars 2020 alors j'ai essayé sans le close, même résultat. mais le QA ne plante pas, (du moins j'ai pas le message du crash comme j'ai déjà eu) J'ai essayé de faire un Open à chaque envoi (un peu comme sur la HC2), mais ça marche pas non plus. On dirait qu'on a perd de la réactivité avec ces sockets. Pourtant tant que tu redémarres pas le serveur TCP, ça marche nickel !!
Krikroff Posté(e) le 8 mars 2020 Signaler Posté(e) le 8 mars 2020 Étrange... Si je trouve le temps en soirée
jojo Posté(e) le 8 mars 2020 Signaler Posté(e) le 8 mars 2020 @jjacques68, ne changerais-tu pas ton pseudo en SocketMen ? 1
jjacques68 Posté(e) le 9 mars 2020 Auteur Signaler Posté(e) le 9 mars 2020 @Krikroff, je vais abuser... désolé... mais tu as pu regarder cette histoire de socket ??
Krikroff Posté(e) le 9 mars 2020 Signaler Posté(e) le 9 mars 2020 Hello, non malheureusement je n’ai pas trouvé le temps mais je n’oublie pas
Krikroff Posté(e) le 12 mars 2020 Signaler Posté(e) le 12 mars 2020 Le 09/03/2020 à 19:50, jjacques68 a dit : @Krikroff, je vais abuser... désolé... mais tu as pu regarder cette histoire de socket ?? Alors... L'idée serait de déclarer une variable dans ton init self.socketClosed = true Puis implémenter 2 méthodes: connect / closeSocket (ou les noms que tu souhaites bien évidement ) Et enfin d'utiliser une méthode principale pour ton send, afin de faire toutes les vérifications d'usage avant le socket:write exemple: function pioneer__vsx__device:send(cmd, expected, callback) if (self.socketClosed == true) then self:connect() end -- This equipments is using the 1st command's <CR> as a trigger to wake up the main CPU self.socket:write("\r", { success = function() self:debug("wake up the main CPU") -- wait 100msec fibaro.sleep(100) self.socket:write("\r"..cmd.."\r", { success = function() -- the function that will be triggered when the data is correctly sent self:debug("data sent") if (type(expected) == 'string') then self:waitForResponse(expected, callback) -- launching a data readout "loop" waitng for expected data else -- no results expected end end, error = function(err) -- the function that will be triggered in the event of an error in data transmission self:debug("error while sending data") self:closeSocket() end }) end, error = function(err) -- the function that will be triggered in the event of an error in data transmission self:debug("error while sending data") self:closeSocket() fibaro.setTimeout(2000, function() self:send(cmd, expected, callback) end) end }) end Du coup, en cas de déconnexion / reco. de ton serveur et au prochain send depuis le HC3, si ça plante le script ferme le socket, puis ré-ouvre et réexecutre la dernière commande. Il faudrait certainement encore "durcir" tout cela mais ok dans mes simulations. Amuse-toi bien 1
jjacques68 Posté(e) le 12 mars 2020 Auteur Signaler Posté(e) le 12 mars 2020 (modifié) Merci pour ton aide, alors de ce que je comprends... ok pour la variable d’état du statut de la socket, avec les méthodes open et close... Pour la méthode send : - tu testes la variable d’état avant tout (avec reconnexion si nécessaire) - Tu fais un premier envoi pour tester la connexion avec le “/r “ (ou autre chose). -> Si celui échoue, tu fermes, (méthode CloseSocket et tu relances la méthode Send au complet après le Timeout - l’état de la variable fera relancer la connexion) -> Si celui réussi, tu envoies la data. -> Si celui réussi, ok super, on attend une éventuelle réponse (“expected=string“) -> Si celui-ci échoue, tu fermes, c’est tout ? tu ne renvoie pas la trame ? Il faudrait pas ajouter un setTimeout avec au préalable CloseSocket dans le deuxième envoi ? exactement comme dans le premier ? Tu utilises le Callback ? Je vois pas trop son intérêt pour le moment... Modifié le 12 mars 2020 par jjacques68
jjacques68 Posté(e) le 12 mars 2020 Auteur Signaler Posté(e) le 12 mars 2020 @Krikroff : ça marche très bien ! je crois que j'ai fait mon très gros gros boulet de base ! J'ai oublié de mettre le "\n" à la fin des trames... erreur de débutant... donc j'avais cette impression que la socket ne se reconnectait pas à la première trame renvoyée !! mais en fait si !!! Simplement je ne la voyais pas sur le serveur ! bref en tout cas la reconnexion fonctionne très bien !! Mille merci pour le temps consacré ! 1
jjacques68 Posté(e) le 12 mars 2020 Auteur Signaler Posté(e) le 12 mars 2020 et j'ai modifié le type du QA en binarySwitch, comme ça j'ai une jolie icone quand la socket crash et une autre quand c'est OK. Par contre, en cas de perte du serveur TCP, il tourne en boucle pour tenter de se reconnecter... c'est le but ! mais j'espère que c'est pas trop gênant... côté ressouces...
Krikroff Posté(e) le 12 mars 2020 Signaler Posté(e) le 12 mars 2020 C’est top bien joué.Côté ressources, cela occupe un thread le temps du setTimeout mais pas bloquant Pourquoi n’utilises tu pas plutôt un type Binary sensor ? Sauf si tu as besoin de faire une action genre On/Off sur ton QA
jjacques68 Posté(e) le 12 mars 2020 Auteur Signaler Posté(e) le 12 mars 2020 ah oui pas bête..., pas besoin de faire de tunOn ou turnOff... avais pas pensé au Sensor
jjacques68 Posté(e) le 17 mars 2020 Auteur Signaler Posté(e) le 17 mars 2020 mouai j’ai encore des difficultés de connexion au serveur ... je vais regardé ça demain. bon une fois que c’est ouvert c’est très stable.
jjacques68 Posté(e) le 18 mars 2020 Auteur Signaler Posté(e) le 18 mars 2020 ouai nan j'arrive pas réouvrir la socket ... j'ai cette erreur lors de la tentative de réouverture : Citation error opening socket : Operation canceled pourtant, côté serveur je vois bien la demande arriver... et le serveur l'accepte bien
jjacques68 Posté(e) le 18 mars 2020 Auteur Signaler Posté(e) le 18 mars 2020 J'ai l'impression que les boucles dans le Open_Socket() et dans le Send() se prennent les pied dans le tapis...
jjacques68 Posté(e) le 18 mars 2020 Auteur Signaler Posté(e) le 18 mars 2020 pffffffffffff... je trouve pas ce qui cloche ! Ce qui est sûr : - La connexion du QA est immédiate si le serveur est déjà lancé. - Si le serveur est redémarré, le QA n'arrive pas à se reconnecter malgré le code qu'on mis en place. Pour le refaire partir, je suis obligé de modifier n'importe quoi dans le QA afin de de pouvoir l'enregistrer et donc de le redémarrer. En gros : le serveur en premier, le QA en deuxième. L'inverse est impossible. Faut redémarrer le QA.
Krikroff Posté(e) le 18 mars 2020 Signaler Posté(e) le 18 mars 2020 Là je suis charrette mais si tu veux tu peux je peux dans la soirée jeter un œil
jjacques68 Posté(e) le 18 mars 2020 Auteur Signaler Posté(e) le 18 mars 2020 si tu as le temps je veux bien, ça fait 5 heures que je fais toutes sortes d'essais... Ce qui est dingue, c'est que j'utilise le bout de code suivant (dan sun autre QA) pour un envoi unique et à la demande, et j'ai aucun soucis !! le truc, c'est dans ce cas là j'ouvre la socket à chaque envoi, chose que je peux pas faire dans l'autre QA, car il y aune grosse quantité de données envoyées à la suite... puis c'est pas normal... function QuickApp:TurnOffPc(Ip) self.sockOff:connect(tostring(Ip), tonumber(self:getVariable("Port")),{ success = function() self:debug("Socket OFF - opened") fibaro.sleep(100) self.sockOff:write("shutdown;YWRtaW5zaHV0ZG93bg==", { success = function() self:debug("Socket OFF - Data sended") end, error = function(err) self:debug("Socket OFF - error sending data : "..err) self:Close_SocketOff() fibaro.setTimeout(3000, function() self:TurnOffPc(Ip) end) end }) end, error = function(err) self:debug("Socket OFF - error opening : ",err) self:Close_SocketOff() fibaro.setTimeout(3000, function() self:TurnOffPc(Ip) end) end }) end
Krikroff Posté(e) le 18 mars 2020 Signaler Posté(e) le 18 mars 2020 Une remarque sur ton QuickApp:TurnOffPc(Ip), tu devrais juste vérifier que le socket et fermé et seulement si faire un connect et pas à chaque fois... Quelle est l'utilité du fibaro.sleep(100) ? Sinon possible d'avoir accès au code qui te pose problème ?
jjacques68 Posté(e) le 18 mars 2020 Auteur Signaler Posté(e) le 18 mars 2020 euh je crois que ça vient d'un copier coller... inutile
jjacques68 Posté(e) le 18 mars 2020 Auteur Signaler Posté(e) le 18 mars 2020 c'est celui sur lequel on avait déjà bossé : function QuickApp:onInit() self.sock = net.TCPSocket({timeout = 2000}) self.ip = self:getVariable("IP") self.port = tonumber(self:getVariable("Port")) self:Open_Socket() end ---------------------------------------------------------------- function QuickApp:Open_Socket() self.sock:connect(self.ip, self.port,{ success = function() self:debug("Socket opened") self.socketClosed = false self:updateProperty("value", true) self:Send("Hello") end, error = function(err) self:debug("error opening socket : ",err) self.sock:close() self.socketClosed = true self:updateProperty("value", false) end }) end ---------------------------------------------------------------- function QuickApp:Close_Socket() self.sock:close() self.socketClosed = true self:debug("Socket closed") self:updateProperty("value", false) end --------------------------------------------------------------- function QuickApp:Send(MaTrame) --reconnect if closed if self.socketClosed == true then self:Open_Socket() fibaro.sleep(3000) end --affiche la trame dans le label self:updateView("LBL_Buffer", "text", tostring(MaTrame)) --envoi la première trame d'essai self.sock:write("\n", { success = function() self:debug("First send = OK") --envoi la data self.sock:write(MaTrame.."\n", { success = function() self:debug("Data send = OK") end, error = function(err) self:debug("error sending data : "..err) self:Close_Socket() fibaro.sleep(500) self:Send(MaTrame) end }) end, error = function(err) self:debug("error sending first : "..err) self:Close_Socket() fibaro.sleep(500) self:Send(MaTrame) end }) end
jjacques68 Posté(e) le 18 mars 2020 Auteur Signaler Posté(e) le 18 mars 2020 J'ai l'impression que l'instruction close() ne libère pas les ressources correctement...
Messages recommandés