Webserver und Qt im Zusammenspiel

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
deets

Kannst du nicht, und das habe ich auch nicht gesagt. Sondern du sollst bottle in einem eigenen Thread starten, im *selben* Prozess.
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Alles klar.

Mitlerweile bin ich von phonon auf den vlc player umgestiegen, der selbst eine remote control anbietet, die man über tcp ansprechen kann.

Grüße,
anogayales
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ein simples Bsp. mit QTcpServer, QWebKit und dem chromeless-Player-Bsp. von youtube --> http://paste.pocoo.org/show/532176/

Die Netzwerksteuerung könntest Du auf HTTP hieven, indem Du dem TcpServer das Protokoll beibringst oder halt ein Webrahmenwerk ala bottle hierfür nutzt. Der Server hat gerade den Vorteil, nur eine Verbindung entgegen zu nehmen - bei den Rahmenwerken musst Du auf Threadsicherheit und mögliche Race-Conditions von Request-Threads zu Player-Hauptthread achten.

@vlc-Player:
Damit kommst Du wahrscheinlich schneller und einfacher zum Ziel.
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Vielen Dank für deine Beispiel Implementierung. Ähnlich sieht es bei mir auch schon aus.

Ein Problem habe ich noch. Ich verbinde mich über den VLC Player über TCP und lese die Antwort des VLC Players in einem Zuge aus:

Code: Alles auswählen

    def _execute_command(self, command):
        self.socket.write("%s \n" % command)
        self.socket.waitForBytesWritten()
        self.socket.waitForReadyRead()
        return self.socket.readAll()
Die Methode _execute_command wird von einem anderen Thread aufgerufen. Diese sieht so aus:

Code: Alles auswählen

@route('/api/player/<command:re:[a-z 0-9]+>')
def player(command):
    return player._execute_command(command)
Das Problem ist, dass immer nur ein Teil der Nachricht übermittelt wird. Als wenn die Methode readAll die Daten zurück gibt ohne darauf zu warten ob vielleicht noch was kommt. Ich weiß so ist TCP spezifiziert und so sollte es auch sein. Wie kann ich dennoch warten bis WIRKLICH nichts mehr kommt, über einen Timer vielleicht?

Mit self.socket.readyRead.connect(handle) kann ich leider nicht arbeiten, denn bottle brauch ja die Daten sofort. Auf Threadsichereit hab ich auch noch nicht geachtet. Ich muss sicherstellen, dass das socket Objekt nur einmal benutzt wird, oder?

Hilft mir http://bottlepy.org/docs/dev/async.html vielleicht weiter?

Grüße,
anogayales
lunar

@anogayales: Gar nicht, denn Du kannst letztlich nie wissen, ob wirklich gar nichts mehr kommt, oder ob die Gegenstelle nicht einfach gerade nur etwas länger braucht, um weitere Daten zu senden. Daher spezifiziert ein Netzwerk-Protokoll immer, wann eine Datenübertragung abgeschlossen ist, e.g. beispielsweise wenn ein bestimmtes Steuerzeichen übertragen wurde, oder die Gegenstelle die Verbindung schließt.

Wie lange Du Daten lesen musst, hängt also vom konkreten Protokoll ab, dass VLC zur Kommunikation nutzt. Dazu müsstest Du die VLC-Dokumentation konsultieren.
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Leider ist die VLC Doku da überhaupt nicht ausführlich. Zumindest finde ich gar keine Doku, eher eine tutorialartige Beschreibung. Auf http://www.videolan.org/doc/ steht was ich vermutet habe:

Code: Alles auswählen

Due to lack of volunteer technical writers, we are unable to provide a proper up-to-date online documentation until further notice.
Sorry for the inconvenience.
Edit: Hab das CLI gefunden:
http://www.videolan.org/developers/vlc/ ... tf/cli.lua oder auch https://github.com/pyrot/vlc/blob/maste ... ntrol/rc.c

Bei ausgewählten Befehlen habe ich durch Testen Schemata festellen können:

Code: Alles auswählen

+----[ Stream 0 ] .... +----[ end of stream info ] 
beinhaltet ein "Paket".

So, es klappt. Leider nur für explizit definierte return messages:

Code: Alles auswählen

        start_time =  QtCore.QTime().currentTime()
        timeout = lambda : (QtCore.QTime().currentTime().msecsTo(start_time)) > -50
        while timeout():
            if command == "info":
                     data = ""
                     while "end of stream info" not in data and timeout():
                         data += self.socket.readAll()
                     if timeout():
                        return data
        return "error"
Hier werden maximal 50 ms gewartet, sonst wird "error" ausgegebn. Wie sinnvoll das ist, muss ich noch testen. :)

Zu Testzwecken hab ich mal das ausprobiert: http://bottlepy.org/docs/dev/async.html

Code: Alles auswählen

def player(command):
    socket = player._execute_command(command) #gibt wirklich ein socket zurück
    body = queue.Queue()
    socket.readyRead.connect(lambda chunk: body.put(chunk))
    return body
Scheintert leider, mit einem

Code: Alles auswählen

NotImplementedError('gevent is only usable from a single thread',)
Grüße,
anogayales
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Die Krux der low level-Implementierung...
Aber mal ehrlich - für Dein beschriebenes Szenario, Player innerhalb des Wohnheims, steuerbar über ein Webfrontend, ist doch der low-level-Kram völlig unerheblich, da Skalierbarkeit, Performance etc. keine Rolle spielen. Über meinen oben beschriebenen Weg per XML-RPC ist die Sache, zugegeben inperformant, relativ schnell zu lösen, und Du musst Dich nicht um einzelne Buckets der TCP-Übertragung scheren:
- Player mit vlc oder QtWebKit-App in Haupt-Thread des XML-RPC-Servers
- API des Players exponiert über XML-RPC
- HTTP-Rahmenwerk genutzt für Webclient oder native XML-RPC-Clients für smartphones gebastelt

Ich glaube, dass Du Dir das Problem unnötig verkomplizierst. Ansonsten ist es natürlich löblich, die Untiefen des Netzwerkstacks durchschauen zu wollen ;)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Und darf ich fragen warum du nicht ein bestehendes, per Smartphone fernsteuerbares Projekt nutzt, sondern das Rad neu erfindest? Ich wollte letztens meinen Musikplayer, Quod Libet via Android-Phone fernsteuern, damit ich bequem im bett liegen kann um Tracks zu überspringen. Eine einfache Google-Suche später war das Problem durch eine entsprechende Software gelöst. Programmieraufwand: 0.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten