TypeError: 'int' does not support the buffer interface

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

Hii,

wie schon im Threndname erwähnt bekomme ich immer folgende Meldung wenn ich mich mit dem Server verbinde und dann eine Nachnicht vom Server zum Client schicken will.

Code: Alles auswählen

TypeError: 'int' does not support the buffer interface
Hier der Server:

Code: Alles auswählen

import socket


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 == "/sensless"):
        print(">> sensless command sended")
        conn.send("sensless line of code")
    else:
        print(">> "+command)
        conn.send(command)
else:
    print("socket closed")
    conn.close()
und der Client:

Code: Alles auswählen

# Echo client program
import socket

HOST = 'localhost'    # The remote host
PORT = 50007              # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
recived = s.recv(1024)
s.close()
print('Received, and closed reciving', repr(data))
Danke für eure Hilfe ich bin noch ein Anfänger und verstehe einfach nicht warum ich diese Fehlermeldung bekomme
BlackJack

@misterjosu: Bei welchem der beiden Programme kommt die Ausnahme denn und wie sieht der *komplette* Traceback aus?
Benutzeravatar
/me
User
Beiträge: 3556
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Bist du sicher, dass die beiden gezeigten Programme laufen und nicht irgendetwas anderes was dann reagiert?

Unter Python 2 läuft das bei mir durchaus (nachdem ich input durch raw_input und recived durch data ersetzt habe).

Ich habe noch einen Tipp der nicht direkt mit dem Problem etwas zu tun hat: Gewöhne dir die überflüssigen Klammern hinter if und while ab. Sie lassen den Code nur unnötig komplexer aussehen.
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

Danke dass ihr so schnell geantwortet habt.

Der Fehler tritt am Server auf, hier die ganze Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "D:\Users\xxxr\Documents\Python\Server\Server_Server.py", line 21, in <module>
    conn.send(command)
TypeError: 'str' does not support the buffer interface
Wenn ihr etwas am Code ändert könnt ihr dass dann bitte posten ?

PS: Ich verwende Python 3
Zuletzt geändert von misterjosu am Montag 1. Juli 2013, 19:10, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo misterjosu,
gesendet werden können nur Bytes. Du mußt also Deinen String encoden.

Grüße
Sirius
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

könntest du mir dass bitte zeigen ?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

So ungefähr:

Code: Alles auswählen

your_str_object.encode("encoding")
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

Danke
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

Tut mir leid, ich habe mich noch nicht mit dem Thema encoding befasst. Kannst du oder jemand anders mir erklären was ich genau machen muss ?

Hier mein überarbeiteter Code:

Code: Alles auswählen

import socket


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 == "/sensless":
        print(">> sensless command sended")
        conn.send("sensless line of code")
    else:
        print(">> "+command)
        command.encode('utf-8')
        conn.send(command)
else:
    print("socket closed")
    conn.close()


Benutzeravatar
/me
User
Beiträge: 3556
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

misterjosu hat geschrieben:

Code: Alles auswählen

        command.encode('utf-8')
        conn.send(command)
Strings sind immutable, also unveränderbar. Der Aufruf von encode ändert nicht den String, sondern führt dazu, dass eine entsprechend kodierte Bytefolge zurückgegeben wird.

Der passende Aufruf wäre also

Code: Alles auswählen

        encoded_command = command.encode('utf-8')
        conn.send(encoded_command)
oder kürzer und ohne Umweg

Code: Alles auswählen

        conn.send(command.encode('utf-8'))
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

Danke !
Benutzeravatar
/me
User
Beiträge: 3556
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

misterjosu hat geschrieben:Danke !
Am anderen Ende solltest du dann das Dekodieren nicht vergessen!
BlackJack

Interessant ist übrigens das die Überschrift was anderes behauptet als der vollständige Traceback.
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

Ok, wie encodet man dass ganze ? mit "recived.encode()" geht das nicht oder ?
misterjosu
User
Beiträge: 44
Registriert: Samstag 29. Dezember 2012, 21:40

Sorry, habs raus mit "decode()" gehts
Benutzeravatar
/me
User
Beiträge: 3556
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.
Antworten