TypeError: 'int' does not support the buffer interface

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Benutzeravatar
/me
User
Beiträge: 3554
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

misterjosu hat geschrieben:Sorry, habs raus mit "decode()" gehts
Was man sich grundsätzlich klar machen musst: Unicode ist keine Codierung, Unicode ist ein Konzept.

In deinem Programm arbeitest du bei Strings mit Unicode. Wenn die Daten das Programm verlassen, dann musst du sie auf irgendeine Art und Weise kodieren damit sie als Bytestream vorliegen den man dann auf die Platte schreiben oder über das Netz schicken kann. Beim Empfangen von Daten muss dann der umgekehrte Vorgang erfolgen. UTF-8 ist dabei ein gute Wahl für die Kodierung, da es den kompletten Unicode-Zeichenraum abdeckt.
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

ok. Jetzt hats ne ganze weile funktioniert und manche kommandos klappen auch schon, allerdings bekomme ich jetzt am server eine "EOL while scanning string literal" Fehlermeldung.

Hier der Server

Code: Alles auswählen

import socket

helplist = "commands: n\
- /kill.connection/                       = schließt den socket des Clients n\
- /call/ [file name]                      = ruft eine datei im Heimverzeichnis des Clients auf n\
- /create.text_file/ [Filename]-[contend] = erstellt eine Datei mit Übergebenem Name und Inhalt n\
- /msg/ [contend]                         = send msg n\
- /shutdown/ [arguments]                  = Client wird heruntergefahren "

HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print('Connected by', addr)
command = ""
while (command != "/ende"):

    command = input()
    
    if (command == "/helplist/"):
        print(helplist)

        
    else:
        print(">> "+command)
        bytestring = command.encode("utf-8")
        conn.send(bytestring)
else:
    print("socket closed")
    conn.close()
Der Client:

Code: Alles auswählen

# Echo client program
import socket

HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
enc_msg = ""
while True:
    recived = s.recv(1024)
    enc_msg = recived.decode()
    enc_list = enc_msg.split("/")
    print(enc_list)
    del enc_list[0]
    prefix = enc_list[0]
    arg = enc_list[1]

    if prefix == "kill.connection":
        pass
    elif prefix == "call":
        pass
    elif prefix == "create.text_file":
        pass
    elif prefix == "msg":
        print("Pakettyp: NACHRICHT")
        print("SERVER >> "+arg)
BlackJack

@misterjosu: Du wirst bei mindestens einem \ am Zeilenende noch „whitespace”-Zeichen *danach* auf der Zeile haben. Ein Grund warum ich diese \ nicht mag und nicht benutze. Python hat doch syntaktische Unterstützung für Zeichenketten die über mehr als eine Zeile gehen. Ich habe auch den Vedacht, dass vor den 'n' am Ende der Zeilen auch ein Backslash stehen sollte.

Der ``else``-Zweig zum ``while`` macht keinen Sinn. Das gehört einfach *hinter* die Schleife. Man möchte ja, dass die beiden Zeilen grundsätzlich immer nach der Schleife ausgeführt werden. Also gehört es eigentlich in den ``finally``-Block von einem ``try``/``finally``.

Beim Parsen der Daten beim Empfänger ist das ``del`` für den ersten Teil überflüssig. Da verrichtet der Rechner einfach nur unnötige Arbeit die man sich durch anpassen der Indizes bei den Zugriffen auf die anderen Teile sparen könnte. Die Verarbeitung verhindert auch, dass man Kommandos absetzen kann bei denen Schrägstriche in den Daten vorkommen. Wenn der Benutzer beispielsweise '/msg/ Dies ist eine 08/15 Nachricht.' eingibt, wird das am Server nicht mehr komplett ausgegeben. Schau Dir mal die Argumente für die `split()`-Methode an. Wobei ich nicht so ganz nachvollziehen kann, warum die '/' überhaupt nötig sind. Man braucht ja eigentlich nur ein Zeichen, welches das Kommando von den (optionalen) Argumenten trennt. Bei den bisherigen Kommandos ist kein Leerzeichen enthalten. Wenn man das beibehält, dann könnte ein einfaches Leerzeichen als Trenner dienen.

Es gibt auch ein Problem mit der Natur von TCP-Verbindungen: Das sind Datenströme und weder `send()` noch `recv()` müssen die kompletten Daten in einem Aufruf übertragen oder empfangen. Das Programm ist also fehlerhaft und funktioniert nur zufällig, wenn es funktioniert.
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

Danke für eure Hilfe.
Die Trennung ist notwendig da man im Grunde genommen Nachrichten und Befehle schicken können soll. Das ganze ist eigentlich auch nur zu Übungszwecken und wird so nie wirklich eingesetzt, außer es bietet sich an, warum dass ganze mit der Übertragung nur zufällig klappt leuchtet mir allerdings nicht ein. Ich dachte TCP wurde extra gemacht um Dateien 100 % Sicher zu übertragen.

Das mit dem "/" als Trennsymbol erscheint mir im Nachhinein auch nicht als akzeptable Lösung, deshalb habe ich die Syntax der zu übertragenden kommandos überarbeitet und ich glaube ich habe eine Lösung gefunden.

Code: Alles auswählen

[command][arg-wert],...]
Ein command wäre daher z.B. [msg] oder [shutdown], wobei bei msg der Text dahinter nicht weiter in ein Argument und einen wert getrennt wird.
PS: ICH SCHREIBE DIE KLAMMERN MIT

Neuer Server:

Code: Alles auswählen

import socket
helplist = "[command][arg-wert]"
HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print('Connected by', addr)
try:
    while True:
        command = input()
        if command == "[help]":
            print(helplist)
        
        else:
            print(">> "+command)
            conn.send(command.encode('utf-8'))
finally:
    print("socket closed")
    conn.close()
und der Client, der aber bist jetzt nur die Nachricht erkennt. Ich poste in so ner halben nochmal den neuen wenn ich weiter bin:

Code: Alles auswählen

# Client 
import socket

HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
    recived = s.recv(1024)
    msg_1 = recived.decode()
    msg_2 = msg_1.replace("[", "")
    msg_list = msg_2.split("]")
    print(msg_list)

    command = msg_list[0]
    raw_arg = msg_list[1]

    if command == "msg":
        print(">>"+raw_arg)
    
BlackJack

@misterjosu: Die Daten werden ja übertragen aber eben nicht zwingend so wie Du beziehungsweise Deine Programme das erwarten. TCP ist ein Datenstrom und sowohl beim Senden wie auch beim Empfangen können (fast) beliebige Teilstücke des Datenstroms verarbeitet werden. Wenn Du `send('eins\n')` und `send('zwei\n')` machst, dann bedeutet das nicht, dass Du auf der anderen Seite zwei `recv()` haben musst bei denen die jeweils gesendeten Daten ankommen. Es kann auch sein, dass Du mit einem `recv()` 'eins\nzwei\n' geliefert bekommst. Oder das Du drei `recv()` brauchst um alles zu lesen, wobei die Aufteilung irgendwie sein kann. Also zum Beispiel 'ein', 's\nzw'. und 'ei\n'. Oder irgendwie anders zerstückelt. Es kann also sowohl passieren, dass Du mehr als ein Kommando auf einmal bekommst, als auch das Kommandos nicht vollständig sind, und man weiter lesen muss bis man alles beisammen hat.

Deine Verarbeitung der eckigen Klammern schliesst jetzt eckige Klammer selbst als Daten in den Argumenten aus.
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

:D Aber es funktioniert :D
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

misterjosu hat geschrieben::D Aber es funktioniert :D
Nein. Das tut es nicht. Damit ein Programm funktioniert, muss es korrekt sein und unter allen Eingaben vernünftig laufen. Dein Programm läuft aber nur, weil dein System zufällig so arbeitet, das kann bei jemand anderen, oder bei Vollmond, schon ganz anders aussehen. Dann schmiert dein Programm einfach ab.
Das Leben ist wie ein Tennisball.
Antworten