Aller au contenu

Question TCPSocket


jjacques68

Messages recommandés

 Oui, respect au personnel hospitalier qui doit se démerder (y'a pas d'autre mot) avec pas grand chose. :13:

Et encore bravo à nos (très très) chers dirigeants pour l'ensemble de leur œuvre depuis trois ans.

 

  • Like 3
Lien vers le commentaire
Partager sur d’autres sites

Le 19/03/2020 à 19:58, Krikroff a dit :

Mais j'ai peur que tu rencontre des soucis à cause d'un risque de désynchronisation, par exemple si tu as un problème de socket tu va bien continuer à alimenter ton tableau mais rien ne te garanti que les items dans le tableau seront tous envoyés

 

Alors petit retour, et bien le principe fonctionne bien.

J'avais le serveur arrêté toute l'après midi car je bossais dessus, et toutes les data ont bien été stockées dans le tableau.

Et le FIFO fonctionne aussi très bien.

 

Il faudrait que je mette un bouton pour faire un RAZ du tableau...

 

Bon faut faire gaffe quand même ! c'est un coup à blinder la mémoire de la HC3, si je pars plusieurs jours et que le serveur est à l'arrêt...

 

ou alors à partir d'un certain nombre d'occurrences dans le tableau, je RAZ automatiquement...

Lien vers le commentaire
Partager sur d’autres sites

  • 3 semaines après...

suite et j'espère fin de cette histoire de socket : 

 

alors d'après mes analyses, il faut bien faire attention, lors des erreurs de lecture, écriture ou autre, à l'emplacement de l'instruction qui rappelle le "connect".

Chose qui avant, n'était pas bien le cas.

Du moins le côté asynchrone des fonctions TCP et des setTimeout fait vite perdre le nord...

 

Donc voici le code complet qui fonctionne visiblement très bien.

Tant pour la connexion, que la reconnexion (provenant d'une coupure côté serveur ou côté HC3), stable et répétitif.

 

Je rappelle que le principe de base est d'avoir une socket ouverte vers un dispositif, en permanence.

De pouvoir faire les READ (de manière à détecter la déconnexion côté serveur).

Et bien sûr du WRITE (du côté client - HC3).

 

Afin de faciliter la gestion ainsi que le risque de perdre des données lors des méthodes de reconnexion, j'utilise un tableau "tampon" qui est rempli par la méthode "AddElement" pouvant être appelée de n'importe où.

L'élément ainsi ajouté, est placé en fin du tableau. 

L'élément envoyé par le WRITE sera le 1er élément du tableau et sera supprimé après l'envoi (FIFO).

Une petite sécurité lors du remplissage de ce tableau, car si la socket ne repart pas rapidement (pour x raisons), ce tableau peut, très très vite, être énorme.

Dans mon cas, j'ai fixé à 500 le nombre max de données dans le tableau.

Après, le 501 ajouté, supprimera le 1er, ainsi de suite...

 

---------------------------------------------------------------------------------------
-- INIT :
--          - Le status du QA = le status de la socket (true/false)
---------------------------------------------------------------------------------------
function QuickApp:onInit()
    __TAG = "QA_"..plugin.mainDeviceId.."_Display Soft"
    self:debug("onInit")
    self:updateProperty("value", false)             --par défaut le QA = false
    self.ip = self:getVariable("IP")
    self.port = tonumber(self:getVariable("Port"))
    self:updateView("LBL_IP", "text", "-----> "..tostring(self.ip))
    self.ListElement = {} 
    self.sock = net.TCPSocket()
    self:CloseSocket()                              --fait un CLOSE
    self:OpenSocket()                               --lance le OPEN
end


---------------------------------------------------------------------------------------
-- OPEN
---------------------------------------------------------------------------------------
function QuickApp:OpenSocket()

    --insert une première valeur qui sera envoyée par le SEND après le OPEN
    table.insert(self.ListElement, "open test")

    --fait le OPEN (connect)
    self.sock:connect(self.ip, self.port, {
        success = function()
            self:updateProperty("value", true)  --passe le QA donc la socket à true
            self:debug("OPEN - connected")            
            self:send()                         --lance le SEND
            self:waitForResponseFunction()      --lance le READ
        end,
        error = function(err)
            self:CloseSocket()
            QuickApp:warning("OPEN ERROR - "..err)
            fibaro.setTimeout(3000, function() self:OpenSocket() end)   --relance le OPEN toutes les 3 secondes
        end
    })
end

---------------------------------------------------------------------------------------
-- CLOSE : par défaut, passe le QA donc la socket à false
---------------------------------------------------------------------------------------
function QuickApp:CloseSocket()
    self.sock:close()    
    self:updateProperty("value", false)
end

---------------------------------------------------------------------------------------
-- READ : permet de choper les déconnexion du serveur
---------------------------------------------------------------------------------------
function QuickApp:waitForResponseFunction()
    self.sock:read({
        success = function(data)
            self:debug("RX - "..data)
            self:waitForResponseFunction()
        end,
        error = function(err)
            QuickApp:warning("READ ERROR - "..err)
            self:CloseSocket()
            fibaro.setTimeout(1000, function() self:OpenSocket() end)
        end
    })
end

---------------------------------------------------------------------------------------
-- WRITE : tourne en boucle tant que QA = true
---------------------------------------------------------------------------------------
function QuickApp:send()
    --si socket OK
    if fibaro.getValue(plugin.mainDeviceId,"value") == true then
        --si element dans tableau
        if self.ListElement[1] then 
            --write
            self.sock:write(self.ListElement[1].."\r", {
                success = function() table.remove(self.ListElement,1) end,
                error = function(err)
                    self:updateProperty("value", false)		--redondance de cette instruction car déjà présente dans CloseSocket. Mais c'est pour être sûr que le temps de cycle ne joue pas de mauvais tour...
                    QuickApp:warning("WRITE ERROR - "..err)
                    self:CloseSocket()
                    fibaro.setTimeout(1000, function() self:OpenSocket() end)   --relance le OPEN
                end
            })
        end
        --et bouclage : ATTENTION A BIEN LE PLACER ICI ! sinon cela entraine un double appel (asynchrone) et ça devient un bordel sans nom !!!!
        fibaro.setTimeout(10, function() self:send() end)
    end    
end

---------------------------------------------------------------------------------------
-- ADD ELEMENT
---------------------------------------------------------------------------------------
function QuickApp:AddElement(element)
    if element ~= "" then
        table.insert(self.ListElement,element)
        if #self.ListElement > 500 then table.remove(self.ListElement, 1) print("purge", #self.ListElement) end
    end
end

 

et donc pour envoyer quelque chose

fibaro.call(ID_du_QA, "AddElement", "TESTS SOCKET")

 

Modifié par jjacques68
Lien vers le commentaire
Partager sur d’autres sites

Il y a 7 heures, Krikroff a dit :

J'ai ma réponse (cf. sujet console ...)

si tu fais allusion a l’histoire de la redondance dans le debug, c’est pas ce self:debug qui en est à l’origine...

C’est que pour afficher ce qui viendrait éventuellement du serveur.

Lien vers le commentaire
Partager sur d’autres sites

Petit complément au sujet du READ :

 

j'ai rencontré quelques effet de bord avec la fonction 

TCPSocket:read()

en effet, j'utilise comme marqueur de fin, dans l'application qui communique avec la socket, le "CR", caract(13).

 

et la HC3, visiblement interprétait mal ce marqueur de fin.

c'est à dire qu'elle trouvait la trame, mais j'avais également un "r" qui était interprété comme une 2ème trame !!

 

du coup avec la fonction

TCPSocket:readUntil(delimiter)

et en lui précisant bien le marqueur de fin dans mon exemple : "\r", il n'y a plus de soucis.

function QuickApp:waitForResponseFunction()
    self.sock:readUntil("\r", {
        success = function(data)
            self:updateView("LBL_Receive", "text", "RECEIVE : "..data)
        	...
        	...
            fibaro.setTimeout(5, function() self:waitForResponseFunction() end)
        end,
        error = function(err)
            QuickApp:warning("READ ERROR - "..err)
            self:CloseSocket()
            fibaro.setTimeout(1000, function() self:OpenSocket() end)
        end
    })
end

 

 

Lien vers le commentaire
Partager sur d’autres sites

×
×
  • Créer...