Kivy: String von .py an Label .kv übergeben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

Hallo
Ich brauche eure Hilfe bei der Frage, wie ich in meinem verkürzt gezeigten Code, einen vom Server zurückgesendeten String (answer) auf der Python-Seite app_client.py an ein Label (id: input) auf der
Kivy-Seite app_client.kv übergeben kann. Zur verkürzten Darstellung habe ich die Klasse Communication weggelassen.
Hier der Code app_client.py:

Code: Alles auswählen

class FirstScreen(Screen):
    def get_communication(self):
        if communication.get_ip_address() is True:
            self.parent.current = "second"
            communication.get_username(self.ids.nickname.text)

            receive_thread = threading.Thread(target=communication.receive)
            receive_thread.start()
            write_thread = threading.Thread(target=communication.write)
            write_thread.start()

        else:
            PopupWindow().open()

class SecondScreen(Screen):
    def receive(self, answer):
        print(answer)
        # self.ids.input.text = answer  # ???




    def write(self):
        communication.write(self.ids.output.text)

    @staticmethod
    def close():
        global connection
        connection = False
        communication.close()
        sys.exit()


class ScreenManagement(ScreenManager):
    """
    def __init__(self, *args, **kwargs):
        super(ScreenManagement, self).__init__(*args, **kwargs)

        @mainthread
        def delayed():
            first_screen = self.get_screen('first')
            second_screen = self.get_screen('second')

        delayed()
    """
    pass


class ClientApp(App):
    def build(self):
        return Builder.load_file("app_client.kv")


class PopupWindow(Popup):
    pass


if __name__ == "__main__":
    communication = Communication()
    app = ClientApp()
    app.run()
und hier ist der Code app_client.kv:

Code: Alles auswählen

ScreenManagement:
    FirstScreen:
        name: 'first'
    SecondScreen:
        name: 'second'

<FirstScreen>
    name: "first"
    BoxLayout:
        orientation: 'vertical'
        padding: 25

        BoxLayout:
            orientation: 'horizontal'
            size_hint: 1, .3
            Button:
                text: '<'
                size_hint: .1, 1
                font_size: 75
                # background_normal: ""
                background_color: 1, .5, .92, 1
                on_release: app.root.current = root.close()

            Label:
                text: 'CHOOSE USERNAME'
                font_size: 50
                canvas.before:
                    Color:
                        rgba: 0.18, .5, .92, 1
                    Rectangle:
                        pos: self.pos
                        size: self.size
            Widget:
                size_hint: .1, 1
                canvas.before:
                    Color:
                        rgba: 1, .5, .92, 1
                    Rectangle:
                        pos: self.pos
                        size: self.size

        GridLayout:
            cols: 2
            rows: 1

            size_hint_y: None
            height: 80
            canvas.before:
                Color:
                    rgba: 1, 1, 1, 1
                Rectangle:
                    pos: self.pos
                    size: self.size

            Label:
                text: 'Username:'
                font_size: 40
                size_hint: .3, 1
                color: 0.18, .5, .92, 1
                pos_hint: {'center': 1}

            TextInput:
                id: nickname
                text: "DMD"
                size_hint: .6, 1
                font_size: 50
                multiline: False

        Button:
            text: '>> Join In'
            font_size: 35
            size_hint: 1, .3
            # background_normal: ""
            background_color: 0.18, .5, .92, 1
            on_release: root.get_communication()

        Label:
            text: 'Support'
            color: 0.18, .5, .92, 1
            halign: 'left'
            font_size: 25
            size_hint: 1, .3
            canvas.before:
                Color:
                    rgba: 1, 1, 1, 1
                Rectangle:
                    pos: self.pos
                    size: self.size

<SecondScreen>
    name: "second"
    output: output
    input: input

    BoxLayout:
        orientation: 'vertical'
        padding: 25

        Label:
            text: "CHAT ROOM"
            font_size: 50

        TextInput:
            id: output
            text: "Your message here..."
            font_size: 25
            multiline: False

        Label:
            id: input				# hier versuche ich die Serverantwort "answer" zu übergeben
            text: "Hello world!"
            font_size: 25

        Button:
            text: ">> Send"
            font_size: 35
            on_release: root.write()

        Button:
            text: ">> Close"
            font_size: 35
            on_release: app.root.current = root.close()
Jede Hilfe ist mir natürlich willkommen :)
Sirius3
User
Beiträge: 18227
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich kenne mich mit Kivy nicht aus, aber auch sonst gibt es noch viele Baustellen. Auch in kivy darf es keine globalen Variablen geben. sys.exit ist sicher der falsche Weg um ein jivy-Programm zu beenden.
Eine Funktion die get_ip_address heißt, sollte nicht True zurückgeben. Auf True prüft man nicht mit `is`.
Dass der Rückgabewert von get_username nicht verwendet wird, läßt befürchten, dass die Funktion auch nicht das macht, was der Name suggeriert. Dass die Threads keine Argumente haben, deutet auch darauf hin, dass hier mit globalen Variablen gearbeitet wird. Das ist bei Threads nochmal gefährlicher.
Benutzeravatar
Dennis89
User
Beiträge: 1506
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

schau mal hier:
https://kivy.org/doc/stable/guide/lang. ... ython-code

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

Wie gesagt, die Klasse Communication fehlt hier. Es wird natürlich alles auch verwendet, was da steht.
Die globalen Variablen sind nur vorerst da enthalten, damit ich es grundsätzlich einmal zum Laufen bekomme.
Danach werde ich versuchen, die rauszuschmeißen.
Zur Funktion kurz:
Es ist eine sehr einfache Server-Client-App (ein kleiner Chatroom).
Mit dem Button '>> Join In' melde ich mich beim Server an. Dann kann ich einen Text schreiben, schicke den über Button ">> Send" zum Server, der mir den Text direkt wieder zurückschickt.
Auf SecondScreen -> def receive(self, answer) kommt derselbe Text wieder an.
Jetzt versuche ich nur noch, den empfangenen Text "answer" an das Label id: input zu übergeben.
So wie ich es hier habe, erhalte ich die Fehlermeldung:

Code: Alles auswählen

 Exception in thread Thread-1 (receive):
 Traceback (most recent call last):
   File "kivy\properties.pyx", line 961, in kivy.properties.ObservableDict.__getattr__
 KeyError: 'input'
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "C:\Program Files\Python310\lib\threading.py", line 1016, in _bootstrap_inner
     self.run()
   File "C:\Program Files\Python310\lib\threading.py", line 953, in run
     self._target(*self._args, **self._kwargs)
   File "C:\Users\dmd__\Documents\Programmierung\PyCharm\Chat-App\client\app\app_client.py", line 46, in receive
     self.second.receive(message)
   File "C:\Users\dmd__\Documents\Programmierung\PyCharm\Chat-App\client\app\app_client.py", line 80, in receive
     hello = self.ids.input
   File "kivy\properties.pyx", line 964, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'. Did you mean: '__setattr__'?
Wo genau ist jetzt das Problem?
Das was ich rausbekommen habe ist, dass ich an die Variable "self.ids.input.text" eine leere Hülle übergebe. Das verursacht den Fehler?
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

@Dennis89
Dein Beispiel konnte ich bei mir umsetzen. Das funktioniert.
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

Habs jetzt so. Leider funktioniert es auch nicht.

Code: Alles auswählen

class SecondScreen(Screen):
    input = ObjectProperty(None)
    def receive(self, message):
        print(type(message), message)
        # hello = self.ids.input
        # hello.text = message
        self.input = message

    def write(self):
        communication.write(self.ids.output.text)

Code: Alles auswählen

<SecondScreen>
    input: input

    BoxLayout:
        orientation: 'vertical'
        padding: 25

        Label:
            text: "CHAT ROOM"
            font_size: 50



        TextInput:
            id: output
            text: "Your message here..."
            font_size: 25
            multiline: False

        TextInput:
            id: input
            text: input.text  # Ist hier der Fehler?
            font_size: 25
            multiline: False

        Button:
            text: ">> Send"
            font_size: 35
            on_release: root.write()
Der Button ">> Send" schickt das Geschriebene an die Klasse Communication (die weiter zum Server, der alles wieder zurück an receive(self, message).
Value message ist ein String.
IST MEIN RECHNER KAPUTT? :)
Benutzeravatar
Dennis89
User
Beiträge: 1506
Registriert: Freitag 11. Dezember 2020, 15:13

Naja, in der Doku sieht das ein bisschen anders aus, ich kopiere dir die Stelle mal hier rein:

Code: Alles auswählen

<Marvel>
  Label:
    id: loki
    text: 'loki: I AM YOUR GOD!'
  Button:
    id: hulk
    text: "press to smash loki"
    on_release: root.hulk_smash()

Code: Alles auswählen

class Marvel(BoxLayout):

    def hulk_smash(self):
        self.ids.hulk.text = "hulk: puny god!"
        self.ids["loki"].text = "loki: >_<!!!"  # alternative syntax
Ich verstehe nicht ganz, wenn du den auf deinen "send"-Button klickst, dann soll sich der Text des Labels ändern? Du rufst aber eine "write"-Funktion auf und der Teil zum ändern des Labels steht in einer anderen Funktion, die nicht aufgerufen wird. Wenn du in die Funktion, die nach dem drücken des Buttons aufgerufen wird

Code: Alles auswählen

self.ids.input.text = "Jetzt steht da ein anderer Text"
schreibst, dann steht da im Label mit der id "input" jetzt ein anderer Text.
Zumindest wars bei mir so.

Der Rechner teilst sich in verschiedene Ebenen auf, ich habe gelernt, dass die Ebene 8 öfters kaputt sei.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

Ja, wie ich schon geschrieben habe, habe ich das auch gemacht. Das was du da gemacht hast, funktioniert ja auch bei mir.
Zur Beschreibung MEINES Problems:
Mit dem Button "Send" in der Klasse SecondScreen wird das was man im TextInput "output" geschrieben hat, in der Funktion SecondScreen "write" ausgelesen und an die Funktion "write" in der Klasse Communication gegeben. Diese Funktion sendet das Geschriebene an den Server. Der Server wieder direkt alles zurück an die Funktion "receive" in der Klasse Communication. Und von da aus wieder zurück an die Funktion "receive" in der Klasse SecondScreen.

Also:
Button "Send" drücken -> SecondScreen:write-> Communication:write -> Server .> Communication:receive -> SecondScreen:receive [-> von hier aus noch an das Label "input" in .kv-File]

Das heißt drücke ich den Button "Send" geht alles Geschriebene an den Chat-Server und der schickt das wieder zurück an alle beteiligten Chat-Teilnehmer.
Soweit funktioniert alles auch fehlerfrei.

Jetzt fehlt noch, den vom Server zurückgesendeten String "message", der in der Funktion "receive" in Klasse SecondScreen ankommt, an das Label "input" in der .kv-Seite zu geben.
Heißt, ich muss den String "message", der hier ankommt:

Code: Alles auswählen

    def receive(self, message):
        print(type(message), message)
        self.input = message
        # hello.text = message
        # self.input = message
an das Label input

Code: Alles auswählen

        TextInput:
            id: input
            text: root.input.text  # Ist hier der Fehler?
            font_size: 25
            multiline: False
übergeben.
Hoffe, das ist verständlich :)
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

Hier ist der gesamte Code. Ist alles noch sehr verbesserungsnötig, wie ja auch Sirius3 schon geschrieben hat. Vor allem die globalen Variablen müssen später noch weg.
-> app_client.py

Code: Alles auswählen

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
import socket
import sys
import threading


BUFFER = 64
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "exit"
connection = True


class Communication:
    def __init__(self):
        super(Communication, self).__init__()
        self.first = FirstScreen()
        self.second = SecondScreen()
        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.IP_ADRESS, self.NICKNAME, self.COUMMUNICATION = str(), str(), bool

    def get_ip_address(self):
        try:
            IP = socket.gethostbyname(socket.gethostname())
            self.client.connect((str(IP), 50505))
            self.IP_ADRESS = IP
            self.COUMMUNICATION = True
        except socket.error:
            self.COUMMUNICATION = False
        finally:
            return self.COUMMUNICATION

    def get_username(self, NICKNAME):
        self.NICKNAME = NICKNAME

    def receive(self):
        global connection
        while connection:
            message = self.client.recv(1024).decode(FORMAT)
            if message == 'NICKNAME':
                self.client.send(self.NICKNAME.encode(FORMAT))
            else:
                self.second.receive(message)

    def write(self, user_output=None):
        if user_output is not None:
            message = f"[{self.NICKNAME}]: {user_output}".encode(FORMAT)
            len_message = str(len(message)).encode(FORMAT)
            len_message += b' ' * (BUFFER - len(len_message))
            self.client.send(len_message)
            self.client.send(message)

    def close(self):
        self.write("exit")


class FirstScreen(Screen):
    def get_communication(self):
        if communication.get_ip_address() is True:
            self.parent.current = "second"
            communication.get_username(self.ids.nickname.text)

            receive_thread = threading.Thread(target=communication.receive)
            receive_thread.start()
            write_thread = threading.Thread(target=communication.write)
            write_thread.start()

        else:
            PopupWindow().open()


class SecondScreen(Screen):
    input = ObjectProperty(None)

    def receive(self, message):
        print(type(message), message)
        self.input = message                          # "message" soll jetzt in das Label "input" auf der .kv-Seite
        # hello.text = message			# Aber nicht so.... :)
        # self.input = message




    def write(self):
        communication.write(self.ids.output.text)

    @staticmethod
    def close():
        global connection
        connection = False
        communication.close()
        sys.exit()


class PopupWindow(Popup):
    pass


class ScreenManagement(ScreenManager):
    """
    def __init__(self, *args, **kwargs):
        super(ScreenManagement, self).__init__(*args, **kwargs)

        @mainthread
        def delayed():
            first_screen = self.get_screen('first')
            second_screen = self.get_screen('second')

        delayed()
    """
    pass


class ClientApp(App):
    def build(self):
        return Builder.load_file("app_client.kv")


if __name__ == "__main__":
    communication = Communication()
    app = ClientApp()
    app.run()
app_client.kv

Code: Alles auswählen

ScreenManagement:
    FirstScreen:
        name: 'first'
    SecondScreen:
        name: 'second'


<FirstScreen>
    BoxLayout:
        orientation: 'vertical'
        padding: 25

        BoxLayout:
            orientation: 'horizontal'
            size_hint: 1, .3
            Button:
                text: '<'
                size_hint: .1, 1
                font_size: 75
                # background_normal: ""
                background_color: 1, .5, .92, 1
                on_release: app.root.current = root.close()

            Label:
                text: 'CHOOSE USERNAME'
                font_size: 50
                canvas.before:
                    Color:
                        rgba: 0.18, .5, .92, 1
                    Rectangle:
                        pos: self.pos
                        size: self.size
            Widget:
                size_hint: .1, 1
                canvas.before:
                    Color:
                        rgba: 1, .5, .92, 1
                    Rectangle:
                        pos: self.pos
                        size: self.size

        GridLayout:
            cols: 2
            rows: 1

            size_hint_y: None
            height: 80
            canvas.before:
                Color:
                    rgba: 1, 1, 1, 1
                Rectangle:
                    pos: self.pos
                    size: self.size

            Label:
                text: 'Username:'
                font_size: 40
                size_hint: .3, 1
                color: 0.18, .5, .92, 1
                pos_hint: {'center': 1}

            TextInput:
                id: nickname
                text: "DMD"
                size_hint: .6, 1
                font_size: 50
                multiline: False

        Button:
            text: '>> Join In'
            font_size: 35
            size_hint: 1, .3
            # background_normal: ""
            background_color: 0.18, .5, .92, 1
            on_release: root.get_communication()

        Label:
            text: 'Support'
            color: 0.18, .5, .92, 1
            halign: 'left'
            font_size: 25
            size_hint: 1, .3
            canvas.before:
                Color:
                    rgba: 1, 1, 1, 1
                Rectangle:
                    pos: self.pos
                    size: self.size

<SecondScreen>
    input: input

    BoxLayout:
        orientation: 'vertical'
        padding: 25

        Label:
            text: "CHAT ROOM"
            font_size: 50

        TextInput:
            id: output
            text: "Your message here..."
            font_size: 25
            multiline: False

        TextInput:
            id: input
            text: input.text
            font_size: 25
            multiline: False

        Button:
            text: ">> Send"
            font_size: 35
            on_release: root.write()



        Button:
            text: ">> Close"
            font_size: 35
            on_release: app.root.current = root.close()

<PopupWindow>
    title: "Popup Window"
    auto_dismiss: False
    size_hint: 0.7, 0.5
    pos_hint: {"x": 0.2, "top": 0.9}

    FloatLayout:
        size_hint: 0.6, 0.8

        Label:
            text: "Es konnte keine Verbindung hergestellt werden."
            text_size: self.width, None
            halign: "center"
            valign: "middle"
            size_hint: 0.6, 0.5
            pos_hint: {"x": 0.2, "top": 1}
            height: self.texture_size[1]
            color: 0.8,0.6,0.1,1
            canvas.before:
                Color:
                    rgba: 0.5, 0, 0, 1
                Rectangle:
                    pos: self.pos
                    size: self.size

        Button:
            text: "Schließen"
            size_hint: 0.8, 0.2
            pos_hint: {"x": 0.1, "y": 0.1}
            on_release: root.dismiss()
Sirius3
User
Beiträge: 18227
Registriert: Sonntag 21. Oktober 2012, 17:20

Nur Konstanten werden komplett GROSS geschrieben, es ist unsinn, den leeren String per str() zu erzeugen, und COUMMUNICATION den Typ bool zuzuweisen ist totaler Quatsch. Nicht initialisierte Attribute wird None zugewiesen und nichts anderes.
Für Socket-Communication braucht man ein Protokoll. Ein recv(1024) liefert 1 bis 1024 Bytes. Wenn Du versuchst, diese UTF8 zu decodieren kann es zu Fehlern kommen, weil UTF8 Zeichen mit mehr als einem Byte codieren kann.
send sendet 1 bis alle Bytes, das muß man also prüfen, ob wirklich alle Bytes gesendet worden sind, oder sendall benutzen.
Wenn man Zahlen mit einer bestimmten Anzahl an Stellen ausgeben will, benutzt man Formatstrings, in Deinem Fall also:

Code: Alles auswählen

message_length = b"%-*d" % (BUFFER, len(message))
Die Funktionsnamen sind immer noch schlmm: get_ip_address würde besser connet heißen, den Rückgabewert prüft man immer noch nicht per `is True`. get_username ist eindeutig ein set_username.

Ich denke Kivy ist keine Ausnahme, was Threadsicherheit betrifft. Man darf von keinem anderen Thread auf die GUI zugreifen.
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

Bis auf das die Themen Threadsicherheit und Socket-Protokoll habe ich soweit alles erstmal verbessert.
Wie man die beiden übrigen Themen besser macht, weiß ich noch nicht genau. Ein kleiner Tip dazu hätte ich da leider auch noch nötig :)

Code: Alles auswählen

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
import socket
import sys
import threading


class Communication:
    def __init__(self):
        super(Communication, self).__init__()
        self.first = FirstScreen()
        self.second = SecondScreen()
        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.ip_adress, self.nickname, self.communication = None, None, None
        self.format = 'utf-8'
        self.connection = True

    def connect(self):
        try:
            IP = socket.gethostbyname(socket.gethostname())
            self.client.connect((str(IP), 50505))
            self.ip_adress = IP
            self.communication = True
        except socket.error:
            self.communication = False
        finally:
            return self.communication

    def set_username(self, nickname):
        self.nickname = nickname

    def receive(self):
        while self.connection:
            message = self.client.recv(1024).decode(self.format)
            if message == 'NICKNAME':
                self.client.sendall(self.nickname.encode(self.format))
            else:
                self.second.receive(message)

    def write(self, user_output=None):
        if user_output is not None:
            message = f"[{self.nickname}]: {user_output}".encode(self.format)
            len_message = b"%-*d" % (64, len(message))
            self.client.sendall(len_message)
            self.client.sendall(message)

    def close(self):
        self.write("exit")
        self.connection = False
        sys.exit()


class FirstScreen(Screen):
    def get_communication(self):
        if communication.connect():
            self.parent.current = "second"
            communication.set_username(self.ids.nickname.text)

            receive_thread = threading.Thread(target=communication.receive)
            receive_thread.start()
            write_thread = threading.Thread(target=communication.write)
            write_thread.start()

        else:
            PopupWindow().open()


class SecondScreen(Screen):
    input = ObjectProperty(None)

    def receive(self, message):
        print(type(message), message)
        self.input = message
        # hello.text = message
        # self.input = message

    def write(self):
        communication.write(self.ids.output.text)

    @staticmethod
    def close():
        communication.close()


class PopupWindow(Popup):
    pass


class ScreenManagement(ScreenManager):
    pass


class ClientApp(App):
    def build(self):
        return Builder.load_file("app_client.kv")


if __name__ == "__main__":
    communication = Communication()
    app = ClientApp()
    app.run()
Benutzeravatar
__blackjack__
User
Beiträge: 13937
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`recv(1024)` ist immer noch falsch. Das geht so schlicht und ergreifend nicht. Du musst ein Protokoll implementieren als Dir überlegen wie Du einzelne Nachrichten aus dem TCP-Datenstrom kennzeichnest und dann Code schreiben der das Nachrichtenformat dann verarbeiten kann.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

??? Was? Ich muss mir ein eigenes Protokoll schreiben. Ich nutze das doch nur privat!
Ich würde auch gern mein eigentliches Problem angehen, wie ich den String message an das TextInput input übergeben kann.
Das funktioniert ja auch noch nicht mal.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was hat das denn damit zu tun? Ohne funktioniert’s halt nicht oder produziert schwer nachvollziehbare Fehler. Und für einen Chat reicht im Zweifel ein readline-basiertes, wie hier schon 1000de Male diskutiert.
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

Ich kümmere mich das sehr gern drum. Ich möchte auch einen vernünftig funktionierenden Code habe. Ein eigenes Protokoll zu schreiben, dauert bei mir aber wohl sau lange.
Da sitz ich Jahre dran. Ich nutze doch ein Protokoll das allgemein gültig ist. So wie ich es habe, scheint das so sehr verbreitet zu sein.

Ich würde mich nur freuen, wenn mir vielleicht auch jemand bei meinem eigentlichen Problem helfen könnte.
Da sieht es nämlich auch nicht so gut aus... :)
Benutzeravatar
Dennis89
User
Beiträge: 1506
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

das mit den Protokollen würde ich nicht vernachlässigen, wenn dir das so ans Herz gelegt wird.

Dann würde ich mal die Threads ganz rauswerfen und die Abfrage der Nachricht regelmäßig mit "Clock" machen:
https://kivy.org/doc/stable/api-kivy.clock.html

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
DMD-OL
User
Beiträge: 327
Registriert: Samstag 26. Dezember 2015, 16:21

Ja, siehe oben.
Benutzeravatar
__blackjack__
User
Beiträge: 13937
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@DMD-OL: Nein, Du benutzt kein Protokoll, das ist ja gerade das Problem. Das Du in der Transportschicht TCP benutzt hat nichts damit zu tun, dass Deine Anwendungsschicht ein Protokoll braucht um tatsächlich funktionieren zu können. Also über den Zufall hinaus dass das manchmal zu funktionieren *scheint*.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Sirius3
User
Beiträge: 18227
Registriert: Sonntag 21. Oktober 2012, 17:20

@DMD-OL: bei `write` hast Du doch schon ein Protokoll implementiert, nur bei receive fehlt das noch.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

DMD-OL hat geschrieben: Donnerstag 7. September 2023, 19:12 Ich kümmere mich das sehr gern drum. Ich möchte auch einen vernünftig funktionierenden Code habe. Ein eigenes Protokoll zu schreiben, dauert bei mir aber wohl sau lange.
Da sitz ich Jahre dran. Ich nutze doch ein Protokoll das allgemein gültig ist. So wie ich es habe, scheint das so sehr verbreitet zu sein.
Du hast nicht verstanden, worum es geht. Du sollst nicht das Internet neu erfinden. Sondern dir darueber klar werden, dass Sockets als Abstraktion DatenSTROEME sind. NICHT Pakete. Auch wenn man von TCP/IP-Paketen spricht, gibt dein OS dir einen Gartenschlauch in die Hand, aus dem mal ein paar Tropfen kommen, mal ein ganzer Schwall. Aber *NICHT* bei jedem mal benutzen eine genau definierte Menge, also in deinem Fall genau *eine* Nachricht. Das ist reiner Zufall, dass das meistens funktioniert. Protokoll meint also hier, dass man auf diesem Datenstrom obendrauf etwas packt, das sicherstellt, dass man immer eine komplette Nachricht empfangen hat. ZB indem man alle Nachrichten konsisten mit einem Zeilenvorschub beendet, und dann kann man auch einfach so lange lesen, bis der kommt, und fertig ist das Protokoll.

Um es nochmal ganz ganz deutlich zu sagen: wenn du 100 Bytes in den Socket schreibst (mit send_all, sonst ist noch nicht mal garantiert, das alles reingeschrieben wird), dann koennen da beim lesen

- 100 byte am Stueck kommen (nimmst du gerade an)
- 1 Byte, 10 Byte, 89 Byte
- 23 Byte, 77 Byte.

Und so weiter.
Antworten