Socket und PETSCII Terminal!?

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Astolas
User
Beiträge: 4
Registriert: Montag 17. Februar 2014, 13:23

Hallo liebe Gemeinde,

Im Rahmen meiner Experimente mit Python und sockets bin ich an meine Grenzen gestoßen. Ziel ist es, ein PETSCII kompatibles Bulletin Board System zu entwickeln.

Also habe ich bisher mit ein paar Chatserver - scripten rumexperimentiert. Verbinden kann ich zu allen Serverscripten von allen Plattformen problemlos. Auch die Verwendung der PETSCII Zeichentabelle sowie PETSCII SEQ dateien (vom Commodore 64) funktioniert tadellos.

Aber spätestens wenns um die Eingabe im Client geht, spaltet sich die Kluft. Texteingabe funktioniert mit Putty und dem Windows - Telnet Client problemlos. Nur auf dem C64 (mit Novaterm 6.5) oder mit CGTerm (Windows PETSCII Telnetclient) ist das nicht möglich.

Woran kann das liegen? Bei allen getesteten Scripten war kein Erfolg in Sicht.
BlackJack

@Astolas: Also ich bin ein wenig verwirrt was genau das Problem ist. Wir sollen jetzt raten warum NovaTerm oder CGTerm mit irgendwelchen Skripten die wir nicht kennen nicht funktionieren?

Falls die irgendwelche Befehle als Zeichenketten erwarten und darauf irgendwie reagieren, muss man natürlich bedenken das PETSCII nicht mal bei der Kodierung der Buchstaben mit ASCII übereinstimmt.
Astolas
User
Beiträge: 4
Registriert: Montag 17. Februar 2014, 13:23

Okay, nehmen wir ein kleines Beispielscript:

Code: Alles auswählen

#!/usr/bin/env python
 
import socket
import thread
import time
 
HOST = "127.0.0.1"
PORT = 23
 
def accept(conn):
    """
    Call the inner func in a thread so as not to block. Wait for a 
    name to be entered from the given connection. Once a name is 
    entered, set the connection to non-blocking and add the user to 
    the users dict.
    """
    def threaded():
        while True:
            conn.send("Please enter your name: ")
            try:
                name = conn.recv(1024).strip()
            except socket.error:
                continue
            if name in users:
                conn.send("Name entered is already in use.\n")
            elif name:
                conn.setblocking(False)
                users[name] = conn
                broadcast(name, "+++ %s arrived +++" % name)
                break
    thread.start_new_thread(threaded, ())
 
def broadcast(name, message):
    """
    Send a message to all users from the given name.
    """
    print (message)
    for to_name, conn in users.items():
        if to_name != name:
            try:
                conn.send(message + "\n")
            except socket.error:
                pass
 
# Set up the server socket.
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.setblocking(False)
server.bind((HOST, PORT))
server.listen(1)
print ("Listening on %s" % ("%s:%s" % server.getsockname()))
 
# Main event loop.
users = {}
while True:
    try:
        # Accept new connections.
        while True:
            try:
                conn, addr = server.accept()
            except socket.error:
                break
            accept(conn)
        # Read from connections.
        for name, conn in users.items():
            try:
                message = conn.recv(1024)
            except socket.error:
                continue
            if not message:
                # Empty string is given on disconnect.
                del users[name]
                broadcast(name, "--- %s leaves ---" % name)
            else:
                broadcast(name, "%s> %s" % (name, message.strip()))
        time.sleep(.1)
    except (SystemExit, KeyboardInterrupt):
        break
Dieses Script funktioniert einwandfrei mit Putty oder dem Windows Telnet Client. Wenn ich jetzt aber einen PETSCII client nehme passiert folgendes:

Bild

und python zeigt diesen fehler an:
Unhandled exception in thread started by <function threaded at 0x0000000001E7C89
8>
Traceback (most recent call last):
File "E:\WinVICE-2.4-x64\PETSCII BBS\zweiter test.py", line 19, in threaded
conn.send("Please enter your name: ")
socket.error: [Errno 10035] Ein nicht blockierender Socketvorgang konnte nicht s
ofort ausgef³hrt werden
Dazu gesagt, wenn ich mich mit den petscii terminal programmen auf z.b. ein mud oder ein anderes bbs einlogge, welches für normales ansi telnet ausgelegt ist, klappt da die eingabe von strings einwandfrei.

Vielleicht hilft das ja etwas weiter
BlackJack

@Astolas: Die Ausgabe im Terminal deutet ja ziemlich stark darauf hin das es einen `socket.error` gibt, denn genau in dem Fall wird immer wieder 'Please enter your name: ' gesendet. Vielleicht ist es keine so gute Idee bei einem Socket was einen Fehler ausgelöst hat, einfach immer weiter zu machen als sei nichts passiert. Als erstes könntest Du mal heraus finden *was* denn beim Empfangen schief läuft in dem Du den Fehler etwas sinnvoller behandelst als ihn zu ignorieren. Mindestens mal ausgeben wäre eine Idee.

Das `thread`-Modul sollte nicht mehr verwendet werden, das ist schon seit einer Ewigkeit „deprecated”. Die Dokumentation verweist auch auf das `threading`-Modul.

Dein Senden und Empfangen ist kaputt weil Du einfach davon ausgehst das jeweils alles mit einem Aufruf gesendet und beim Empfangen in einem Aufruf empfangen wird was auf der anderen Seite (vielleicht) in einem Aufruf gesendet wurde. So funktioniert die TCP-API aber nicht. Das ist ein Datenstrom und bei einem `recv()`-Aufruf kann man einen beliebigen Ausschnitt aus dem Strom bekommen. Im Extremfall jedes Byte in einem eigenen Aufruf. Ein Programm was damit nicht klar kommt ist fehlerhaft.

Das ganze ist auch superunübersichtlich weil es nicht ordentlich auf in sich abgeschlossene Funktionen aufgeteilt ist und veränderbare Datentrukturen auf Modulebene verwendet. Funktionen sollten ausser Konstanten nur Werte verwenden die als Argumente übergeben wurden.
Astolas
User
Beiträge: 4
Registriert: Montag 17. Februar 2014, 13:23

Na, das Script war nur als Beispiel gewählt, hätte auch mit allen anderen Serverscripten nicht funktioniert... Aber durch ein wenig rumprobieren hab ich dann rausgefunden, was da nicht funktioniert.

Hier die Lösung: Die PETSCII Clients arbeiten anders als normale Telnet Clients. Heutige Telnet Clients senden die Stringkette erst nachdem man [ENTER] gedrückt hat. Die PETSCII Clients übertragen aber jeden Buchstaben einzeln. Drückt man zum Beispiel E, so wird eben E in Echtzeit an den Server gesendet. Das gleiche passiert auch mit Steuerzeichen wie die F Tasten.

Ist also kein Python Problem, sondern eine Frage, wie man die Informationen verarbeitet.

Trotzdem nochmal danke für die Hilfe.
BlackJack

@Astolas: Es ist also exakt das Problem was ich beschrieben habe: Ein TCP verarbeitendes Programm muss damit klarkommen können das jedes Byte einzeln gelesen wird (und auch gesendet) sonst ist es fehlerhaft.

Und das gilt auch für „normale” Telnet-Clients, denn dass das gezeigte Skript mit denen „funktioniert” ist nur Zufall. Lokal oder im lokalen Netz mag das so scheinen als wenn das funktioniert, aber wenn man das mal bei hoher Last und über mehr als nur einen lokalen Router laufen lässt, wird das auch mit „normalen” Terminal-Programmen nicht wie gewünscht funktionieren.
Astolas
User
Beiträge: 4
Registriert: Montag 17. Februar 2014, 13:23

Ja, das wirds wohl sein ^^ Sei ein wenig nachsichtig ^^ Ich hab die Angewohnheit, wenn ich ne neue Sprache lernen möchte, denke ich mir n großes Projekt aus und versuche es Stück für Stück umzusetzen.
Antworten