PHP Client Socket Raspberry Pi-IPS / Windows-IPS

…das Ganze lässt mich noch nicht so richtig los…

Gedankengang:
Wenn eine Socket-Verbindung erstellt wird, bekommt man ja eine Art Handle (resource) zurück und dann gibt es noch eine gewisse „Trägheit“, wenn ich diese Verbindung nicht am Ende der Funktion mit Close schließe.
Mir geht es ja insbesondere darum, dass bei sehr schneller Abfolge von Abfragen, diese Verbindung nicht immer wieder aufgebaut und am Ende des Skriptes geschlossen wird. Dieses halte ich für den wirklichen „Zeitfresser“.

Wenn ich den „Handle“ mit SetBuffer/GetBuffer nutze, könnte es dann sein, dass beim nächsten zeitlichen nahen Durchlauf des Skriptes dieser noch gültig ist?

Hat über die Zeit x keine Kommunikation stattgefunden, dann ist es ja okay wenn dann die Verbindung wieder erstellt wird…

Joachim

Nachtrag: Gibt ja zumindest den „SO_KEEPALIVE“-Parameter…

Ich glaube nicht dass das funktioniert den handle in einen Buffer zu schreiben.
Weil ja wenn das Script durchlaufen wurde, alle genutzten Ressourcen freigegeben werden. Damit ist das handle dann ungültig.
Michael

…die Frage ist doch, wer stellt diesen Handle zur Verfügung?
Beispiel: Bei den jeweiligen I2C-Devices macht das PIGPIO, d.h. ich „merke“ mir diesen und kann das Device darüber im Laufe des laufenden Programmes immer wieder damit ansprechen…

Doch woher kommt der Handle für den Socket? Kommt er von der Gegenstelle, dann besteht doch durchaus die Möglichkeit, dass ich diesen über eine gewisse Zeit auch nutzen könnte…

Joachim

Wenn das Script durchlaufen wurde, wird der aktuellen PHP Prozess ja beendet. Wie soll da noch ein Socket existieren? Die TCP Verbindung wird also immer geschlossen.
Der handle ist ja nur ein Zeiger auf diese Verbindung, somit wird das nix.
Michael

…es ist ein Stück weit frustrierend…

Die „resource“ lässt sich schon gar nicht mit „SetBuffer“ sichern, wahrscheinlich weil es eher ein Objekt ist. Die Frage dabei für mich war ja, wer diese „resource“ vergibt: Das PHP auf dem IPS-Rechner - dann ist diese mit Ablauf der Funktion verschwunden oder ist es etwas was von der Gegenstelle vergeben wird - dann hätte zumindest die Chance bestanden, dass dieses bei schneller Abfolge von Kommunikation noch erhalten geblieben wäre…

Der IPS-ClientSocket wäre wahrscheinlich von der Performance besser geeignet, weil der Kanal offen bleibt. Hier ergeben sich aber durch die asynchrone Datenübertragung besondere Herausforderungen. Da die Datenanforderungen jedoch aus verschiedenen Funktionen kommen und teilweise sehr viel Traffic verursachen, mag ich mir gar nicht ausmalen was dabei herauskommt, wenn man den Rückgabewert wieder den jeweiligen Funktionen zuordnen möchte.
Liegt vielleicht auch an der Kommunikation die man da aufbauen möchte und ob die Rückgabewerte immer schlüssig einer Quelle zugeordnet werden können. Bei diesem Projekt würde ich das eher kritisch sehen…

Der PHP-ClientSocket läuft gut, die Daten können sauber zugeordnet werden. Jedoch macht sich bei vielen Datenanfragen der Anmeldeprozess schon deutlich bemerkbar. Dazu ein Beispiel: Im ersten Ansatz hatte ich bei RGB-Stripes den neuen Farbwert in drei Datenübertragungen abgearbeitet, dabei war der sukzessive Farbwechsel - Farbe für Farbe - deutlich sichtbar. Ich habe das dann in eine Datensendung gepackt und es erfolgt visuell ein Farbwechsel.

Aus der Not heraus habe ich jetzt sehr kommunikationsintensive Funktionen - die in sich geschlossen sind - mit einem eigenen ClientSocket versehen, insbesondere auf Windows stellt mich das aber nicht zufrieden…

Joachim

@IPS-Team: Kann man den IPS-ClientSocket nicht auf eine „Synchrone“ Datenübertragung erweitern???

Wie soll das funktionieren ?
Woher soll IPS wissen worauf es in dem ankommenden Stream achten soll um es deiner Funktion zurückzugeben.

Es ist die Aufgabe eines Splitters, alle ForwardData von Devices zu synchronisieren und ggfls. auch die Antworten des IO-Sockets.

Kannst natürlich auch jeder Geräte-Instanz einen IO spendieren, aber ob deine Gegenseite 45, 50, 70 xxxx TCP-Verbindungen gleichzeitig offen halten kann ? Glaube kaum :wink:

Michael

…ach Michael, dass weiß ich doch auch nicht! Es ist die Verzweiflung die da aus mir spricht (bzw. schreibt)…:smiley:

Wenn dieser IPS-ClientSocket nur den geöffnete Kanal bereitstellt (das was ich mit $fp = stream_socket_client(„tcp://“.$Host.":".$Port, $errno, $errstr, 5); halt öffne), dann könnte ich ihn genauso ansprechen wie im Skript, eben auch mit der genaue definierte Antwortlänge ($buf = fgets($fp, $ResponseLen + 1);)…

Joachim

Funktioniert das denn zu 100%.
Oder kann es sein dass du auch dort anstatt einer Antwort mal eine Nachricht von den IO-Pins empfängst.
Wenn das wirklich perfekt läuft, kannst du das mit dem IPS-IO auch relative einfach umsetzen.
Ich schreib nachher mal etwas.
Michael

…im Prinzip läuft das so:

  • den IPS-ClientSocket versende ich zum Start lediglich nur, um ein Kommando zu senden von welchen GPIO ich eine Notification haben möchte wenn dort eine Pegeländerung eintritt. Im ReceiveMessage kommt dann jede Minute das StayAlive-Signal der Notification und wenn eine Pegeländerung eintritt eine (oder mehrere) Datensendungen. Deswegen muss der Kanal immer offen bleiben. Je nach Datenlage wird daraufhin über den PHP-ClientSocket die eigentlich Datenkommunikation abgewickerlt.
  • Über den PHP-ClientSocket sende ich alle anderen Kommandos. In PIGPIO ist für Kommando immer definiert, wie viele Zeichen die Antwort hat. Die Antwort wird dann sofort ausgewertet und der relevante Wert als Rückgabe an die aufrufende Funktion übergeben.

Es kommt nicht vor, dass Antworten auf die Anfrage vom PHP-ClientSocket auf dem IPS-ClientSocket ankommen oder das Ergebnisse in der falschen Reihenfolge kommen, weil ja dort explizit auf die definierte Anzahl von Daten gewartet wird…
Die Trennung in Notification-Socket und Command-Socket ist von dem PIGPIO-Entwickler. Das liegt im Wesentlichen daran, dass die Datensendungen aus dem Notifications - wenn sie geballt kommen weil z.B. der Taster stark prellt - kaum von Kommando-Antworten zu unterscheiden sind, insbesondere wenn sie sich dazwischen schummeln.

Ich habe mich nach Deiner Angabe weiter oben noch mal sehr stark damit auseinandergesetzt, wie ich den Mechanismus zur Trennung von Komando-Antwort und Notification im IPS-ClientSocket auf saubere Beine zu stellen, bisher ist mir das aber nur unzureichend gelungen. Selbst wenn mir das sicher gelingen würde, dann wäre ja die nächste Hürde, diese Kommando-Antwort wieder der jeweiligen Funktion zuzuordnen, die den Wert brauchte…

Bisher führte diese Verfahrensweise zu keinen mir bekannten Probleme (siehe GPIO-Modul). Jetzt kam die Erweiterung mit dem DS2482 (I²C->1-Wire) der aber je nach Anzahl und Art der Sensoren (intern) eine Menge Traffic produziert.
Dazu einige hilfreiche Funktionen wie ein I²C-BusScan und ein 1-Wire-BusScan, die zwar funktionieren aber dennoch spürbar Zeit benötigen weil dort hunderte Mal das öffnen des PHP-ClientSocket durchgeführt werden muss…
Ist vielleicht ein Luxus-Problem - weil es ja funktioniert - würde aber gerne dort die Performance verbessern…:wink:

Joachim

Dann vergiss meinen Post zu meiner Idee.
Wenn sie sich dazwischen schummeln funktioniert das nicht, weil meine Idee war eine Art Weiche im ReceiveData.
Wenn du etwas gesendet hast, die Daten so lange in einen anderen Buffer leiten, bis deine SendeFunktion die Weiche zurückstellt.
Das klappt aber nicht wenn zwischendurch eine Notification empfangen wird.
Michael

…ich bin ja noch dabei Notifications und Befehle voreinander zu trennen. Es gibt aber auch ein paar Kommandos, deren Antwortlänge ich bei dem PHP-ClientSocket berechnen kann, wenn er aber „mittendrin“ kommt, dann könnte ich zwar erkennen, dass es eine Antwort mit variabler Länge ist, da ich aber zunächst einmal die Frage dazu nicht kenne, könnte das dann schiefgehen. Aber vielleicht fällt mir ja auch dazu noch etwas ein…

Aber ich wollte noch etwas anderes: Du hast oben geschrieben, dass ich ein Return von einem normalen Child zum Splitter benutzen könnte. Das klingt auch interessant…
Hättest Du dafür ein Beispiel parat?

Joachim

Paresys GitHub (IOTest)
oder die Doku.
Oder hier:
Device


            $ret= $this->SendDataToParent($JSONString);
            if ($ret === NULL) // Falls der Splitter einen Fehler hat und 'nichts' zurückgibt.
            {
                $this->SendDebug('Response', 'No valid answer', 0);
                return NULL;
            }
            $result = unserialize($ret); //Damit nicht nur Strings, sondern auch Array und Objekte funktionieren.
            $this->SendDebug('Response', $result, 0);
             return $result

Splitter

 public function ForwardData($JSONString)
    {
        $Data = json_decode($JSONString);

        // Irgendwas machen... Daten senden Antwort lesen etc...

       $Response = array('bla','bla','test');
       return serialize($Response);

    }

Michael

PS: Deine Idee mit dem Handle habe ich mal ausprobiert. Ich lasse jetzt den PHP-Socket solange offen wie das ‚Script‘ läuft.
Da ich mit Authentifizierung arbeite, brauch ich mich dann nicht 10x anmelden, wenn ich mehrere Befehle senden will :slight_smile:

Beispiel:


class SqueezeboxDevice extends IPSModul
{
    private $Socket = false;

    public function __destruct()
    {
        if ($this->Socket)
            fclose($this->Socket);
    } 
    protected function SendDirect($Data)
    {
           $this->SendDebug('Send Direct', $Data, 0);

            if (!$this->Socket)
            {
                $this->Socket = @stream_socket_client("tcp://", $errno, $errstr, 1);
                if (!$this->Socket)
                    throw new Exception('No anwser from LMS', E_USER_NOTICE);
                stream_set_timeout($this->Socket, 5);
            }
            fwrite($this->Socket, $Data);
            $result = stream_get_line($this->Socket, 1024 * 1024 * 2, chr(0x0d));
            $this->SendDebug('Response Direct', $result, 0);
            if ($result === false)
                throw new Exception('No anwser from LMS', E_USER_NOTICE);
    }

}

…das ist ja super!!

Habe versucht es nachzustellen:

class GeCoS_IO extends IPSModule
{
 	private $Socket = false;
	
	public function __construct($InstanceID) 
	{
            	parent::__construct($InstanceID);
	}
	
	public function __destruct()
	{
		if ($this->Socket)
		    	fclose($this->Socket);
	} 
	
	public function Create() 
	{

…bekomme jetzt aber nicht einmal das Konfigurationsformular…

Es wird etwas geöffnet, Hinweis: „Dieses Modul hat keine Eigenschaftenseite“. Im Debug sehe ich das etwas läuft - ist aber irgendwie „murks“…

Joachim

…läuft jetzt! Super Arbeit!:slight_smile:

Joachim