@MajorPayne: Die lustige Welt der Socket-Programmierung. Wo alles irgendwie umständlich ist und fehlerhafte Programme laufen können, bis sie dann endlich mal über den Fehler stolpern.
Erst einmal, was heisst abstürzen? Die Beschreibung klingt eher nach hängen bleiben. Und wirklich *hart* oder kann man das Programm eventuell doch ”sanft(er)” beenden als den Prozess vom Betriebssystem abzuschiessen? Was hast Du probiert? <Strg>+<C> bricht das Programm nicht ab? Hast Du mal `print`-Anweisungen eingefügt um zu sehen was noch ausgeführt wird, also ob es schon bei den `send()`-Aufrufen hängt oder erst beim `recv()`?
Da kommen wir dann auch schon zu den lustigen Eigenschaften dieser beiden Methoden. So wie Du das geschrieben hast, ist weder garantiert das die Daten alle gesendet werden, noch das die Antwort komplett empfangen wird.
`send()` kann laut Spezifikation weniger senden als man übergeben hat. Also in diesem Fall auch 0 Bytes von dem einen Byte was jeweils übergeben wurde. Die Methode gibt die Anzahl der gesendeten Bytes zurück und man muss in einer Schleife solange immer wieder den verbleibenden Rest senden bis wirklich alles übergeben werden konnte. Netterweise braucht man diese Schleife nicht selbst schreiben, sondern kann die `sendall()`-Methode verwenden. Die macht das schon.
`recv()` empfängt mindestens ein Byte und maximal so viele wie man als Argument übergeben hat. Man muss das also, so ähnlich wie bei `send()` so lange aufrufen bis man mindestens seine komplette Nachricht beisammen hat, denn im Extremfall kann jeder Aufruf auch nur *ein* Byte aus dem Datenstrom liefern. Andererseits, kann es bei einer grösseren Angabe von Bytes die empfangen werden sollen, auch solange blockieren bis die alle angekommen sind, oder zumindest bis eine Zeitüberschreitung auftritt. Von der man so allerdings erst einmal nicht sagen kann wie lange die dauert. Da das Beispiel aus der Dokumentation deutlich weniger als 252 Bytes als Antwort beschreibt, kann es sein, dass das Programm hier einfach hängt weil es auf mehr Daten wartet als da kommen.
Was auch noch passieren kann, zumindest bei Terminals/Terminalemulatoren ist dass das läuft, aber die Binärdaten die da einfach 1:1 ausgegeben werden das Terminal in einen ”komischen” Zustand versetzen, so dass es so aussieht als würde das Programm nicht mehr laufen, und das Terminal nicht mehr für Eingaben benutzbar sein. Die Ausgabe der Binärdaten würde man besser als `repr()`-Darstellung machen oder in eine Hexadezimaldarstellung umwandeln (siehe das `binascii`-Modul).
Argh. Und *jetzt* sehe ich gerade das die Daten die gesendet werden falsch sind. Die `n*`-Namen sollten jeweils an *einen* Bytewert gebunden werden, also an eine ”Zeichen”kette der Länge 1 wo das ”Zeichen” den Bytewert besitzt der gesendet werden soll. '0x05' enthält aber vier Bytes und zwar die ASCII-Werte für 0, x, 0, und 5. Du möchtest an der Stelle aus der 0 einen \ machen:
Code: Alles auswählen
In [1]: import binascii
In [2]: '0x05'
Out[2]: '0x05'
In [3]: len('0x05')
Out[3]: 4
In [4]: list('0x05')
Out[4]: ['0', 'x', '0', '5']
In [5]: '\x05'
Out[5]: '\x05'
In [6]: len('\x05')
Out[6]: 1
In [7]: list('\x05')
Out[7]: ['\x05']
In [8]: binascii.b2a_hex('\x05')
Out[8]: '05'
In [9]: binascii.b2a_hex('\x05\x15\x00\x05')
Out[9]: '05150005'
Wie man sieht musst Du auch nicht die einzelnen Bytes jeweils an einen Namen binden, sondern man kann auch eine ”Zeichen”kette mit allen Bytes angeben.
*Vorsicht*: Auch wenn das dann mit ansonsten unverändertem Quelltext funktionieren sollte, die ganzen anderen Punkte gelten trotzdem. Das würde dann nur zufällig funktionieren, kann aber jederzeit über die Eigenheiten von `send()` und `recv()` stolpern!
Am einfachsten wird es wenn man sich von dem Socket-Objekt mit der `make_file()`-Methode ein Dateiobjekt geben lässt, denn `read()` und `write()` auf Python's Dateiobjekten garantieren das alle Daten geschrieben werden (oder eine Ausnahme ausgelöst wird wenn das nicht geht), und die angegebene Anzahl von Bytes gelesen werden (sofern sie vorhanden sind, also weniger wenn vorher das Dateiende erreicht wird).
Namen durchnummerieren ist übrigends ein „code smell“. An der Stelle möchte man eigentlich eine Datenstruktur verwenden. Oft ist das eine Liste.