Protokoll für Audio und Video Streaming?

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Meinen Messagebroker könnte ich erweitern. Durch readline ist er zur Zeit auf Messages ohne EOL eingeschränkt. Das kann man ändern.
Dann könnte man für die Clients verschiedene Messagetypen machen:

JSON: zur Zeit ist die Übertragung auf JSON serialisierbare Parameter beschränkt
BYTES: damit kann man dann eine Message übertragen, die aus einem Byte-Array beesteht. Da könnte man beliebige Daten übertragen, wie JPG, PDF, MP3
BYTES_AND_JSON: damit kann man dann Messages übertragen, deren erster Parameter ein Bytearray ist und die restlichen sind dann JSON serialisierbar.

Bzw. BYTES_AND_MAYBE_JSON würde reichen. Ein abschließendes Nullbyte könnte signalisieren, dass nach dem Bytearray nichts mehr kommt.
Oder auch, dass das anschließende Byte den Typ des folgenden Parameters markiert. Damit lasssen sich Bytearrays und JSON beliebig gemischt übertragen.

also hätten wird dann nur mehr die Typen:

JSON
MIXED

wobei dann MIXED jeweils eine Kennung JSON und BYTES pro Parameter hat.

Man würde dann drei Übertragungskanäle haben:

Kommandokanal (ID_REQUEST,SUBSCRIBE)
Kommunikationskanal (JSON)
Datenkanal (MIXED) mit einem extra Kanal dafür würde dann die übrige Kommunikation nicht eingeschränkt sein.

Die Frage ist nun, wie würde man Audio und Video Streaming übertragen? Wohl am Besten eine eigenständige Applikation, die vom Messagebroker die IP Adressen der Teilnehmer erhält? Mit update, wenn sich ein neuer Teilnehmer anmeldet?
BlackJack

@Alfons Mittelmeyer: JSON, BYTES, BYTES_AND_JSON könnte man auch MessagePack zum serialisieren nehmen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Danke für die Info. MessagePack mit pip install installieren, geht auf meinem MK808B nicht und von Source compilieren und linken habe ich keine grosse Lust.

Die Lösung ist mir bereits eingefallen. Bisher habe ich zum subscriben von Messages folgende Funktionen:

request_ids((id1,id2,id3,...,idn))
subscribe((id1,id2,id3,...,idn))

Da mache ich einfach noch folgende zwei dazu:

request_ids_bytes((id1,id2,id3,...,idn))
subscribe_bytes((id1,id2,id3,...,idn))

Für den Router oder Messagebroker macht das keinen Unterschied. Aber die Clients wissen dann, dass sie das anders serialisieren müssen. Der send Befehl soll dann eine Parameterliste haben. Bisher war ein einfach ein x beliebiger Parameter - auch Tuple oder Liste oder sonst etwas.

Für Bytearrays reingemixt, würde das dann etwa so ausssehen:

Code: Alles auswählen

send(id,[5,”Name”,byte_array1,8,Byte_array2,”Test”])
Und die Message würde der Client dann umwandeln in:

Code: Alles auswählen

[[5,”Name”,”{}”,8,”{}”,”Test”],byte_array1,byte_array2]
Und so kann man es serialisieren und auch wieder rückwandeln. Ist doch easy oder?
BlackJack

@Alfons Mittelmeyer: Also ich habe im Package-Index auf Anhieb zwei Module in reinem Python für MessagePack gefunden.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Und ich hab die Serialisierung mit diesen paar Zeilen Code gelöst:

Code: Alles auswählen

    def _send_bytes(self,message_id,message):

        buf = b''
        for i in range(len(message[1])):
            if type(message[1][i]) is bytearray or type(message[1][i]) is bytes:
                buf += len(message[1][i]).to_bytes(4,'big')+message[1][i]
                message[1][i] = "{}"
        json_message = bytes(json.dumps(message),'utf-8')
        message = message_id + len(json_message).to_bytes(4,'big')+json_message+buf
        buf = None
        self.sendall_len(self.socket,message)
Habe schon mal ein JPEG Bild mit 5 MB übertragen - Datei lesen, übertragen, und wieder speichern. Dauerte nur etwa eine halbe Sekunde.

Zur Erläuterung: message[0] einthält die Message ID und interessiert vorerst wenig. message[1] ist die Liste mit den Parametern und die gehe ich durch:

Code: Alles auswählen

        for i in range(len(message[1])):
            if type(message[1][i]) is bytearray or type(message[1][i]) is bytes:
Und wenn es Bytes sind oder ein Bytearray, dann hänge ich das mit vorangestellter Längenangabe an einen Buffer und ersetzte den Parameter in der Liste durch "{}":

Code: Alles auswählen

                buf += len(message[1][i]).to_bytes(4,'big')+message[1][i]
                message[1][i] = "{}"
Und dann brauche nur noch die Messageblöcke zusammensetzen. Dabei wird die Message mit den durch die Markierung "{}" ersetzten Byte Blöcken in JSON gewandelt und Bytes und nach der Message ID (das ist die in Bytes mit dem Message Broker vereinbart) als erter Block auch mit Längenangabe den anderen Byte Blöcken vorangestellt:

Code: Alles auswählen

        json_message = bytes(json.dumps(message),'utf-8')
        message = message_id + len(json_message).to_bytes(4,'big')+json_message+buf
Und dann brauche ich das nur noch mit vorangestellter Gesamtlängenangabe senden:

Code: Alles auswählen

        self.sendall_len(self.socket,message)
Weiss nicht warum man statt ein paar Zeilen Code gleich immer irgendwelche Packs braucht. Um die mit einzupassen muss man doch sicher auch einige Zeilen Code schreiben.
BlackJack

@Alfons Mittelmeyer: Man verwendet halt lieber einen Standard statt selber etwas zu basteln was dann nicht so gut ist, oder extra dokumentiert werden muss, oder nicht mit anderen Sprachen zusammenarbeitet ausser man implementiert das selbstgebastelte da auch, …

Wenn ich das richtig sehe darf jetzt aber niemand auf die Idee kommen "{}" tatsächlich als Parameter senden zu wollen‽

Man könnte auch überlegen JSON insgesamt durch MessagePack zu ersetzen, dann braucht man auch keine Länge manuell davor setzen und man könnte die Message-ID direkt in MessagePack kodieren und wenn die als erstes steht, dann muss man auch gar nicht die komplette Nachricht dekodieren um sie auszulesen. Wobei das die API von `umsgpack` nicht direkt hergibt.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:Wenn ich das richtig sehe darf jetzt aber niemand auf die Idee kommen "{}" tatsächlich als Parameter senden zu wollen‽
Nein, das wäre dann nur, wenn man auch Bytes benützt. Da sollte ich mir vielleicht noch eine ausgefallenere Kennung einfallen lassen. Man könnte ja auch ein Dictionary machen mit {"\n":"}{"}
BlackJack hat geschrieben:Man könnte auch überlegen JSON insgesamt durch MessagePack zu ersetzen, dann braucht man auch keine Länge manuell davor setzen und man könnte die Message-ID direkt in MessagePack kodieren und wenn die als erstes steht, dann muss man auch gar nicht die komplette Nachricht dekodieren um sie auszulesen. Wobei das die API von `umsgpack` nicht direkt hergibt.
Naja, wenn die gleich das MessagePack mit Python ausliefern würden wäre nicht schlecht, aber wieder von Source kompileren, mag ich jetzt nicht. Für tkinter hatte ich schon über einen Tag gebraucht, bis es dann richtig lief.

Mit dem Messagebroker könnte man wahrscheinlcih auch ein Dictionary mit MP3 Dateien senden. Ich hab es nur bis in zweitoberste Ebene gemacht, also nur ein Bytesparameter oder ein Tuple oder eine Liste mit Bytes Parametern aber nicht wieder eine Unterliste mit Bytes Parametern.
Zuletzt geändert von Alfons Mittelmeyer am Donnerstag 17. September 2015, 13:24, insgesamt 1-mal geändert.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

BlackJack hat geschrieben:@Alfons Mittelmeyer: Also ich habe im Package-Index auf Anhieb zwei Module in reinem Python für MessagePack gefunden.
the more they change the more they stay the same
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Ist nicht übel. Sollte die Serialisierung konfigurierbar machen, also einfach Funktionsaustausch. Den Messagebroker interessiert sie sowieso nicht, außer die ersten 4 Bytes sind die Länge und die zweiten 4 Bytes die Message ID. Den Rest können die Clients frei wählen. Lediglich die Steuerkommandos mit Übergabe von IP-Adresse oder Message ID Listen sind nicht frei wählbar und mit JSON realisiert. Könnte man aber auch anpassbar machen.
Antworten