netzwerk.py
netzwerk.py
—
Python Source,
5 KB (5932 bytes)
Dateiinhalt
import socket,sys # Server-/Systemmodul
from threading import Thread
from visual import *
PORT=50000
if sys.version_info.major < 3:
PYTHON_NEW = False
else:
PYTHON_NEW = True
##########################
class udpServer(Thread, socket.socket):
"""modelliert UDP-Server, der den PORT als Argument erhaelt."""
def __init__(self,port):
"Konstruktor"
Thread.__init__(self)
socket.socket.__init__(self, socket.AF_INET, socket.SOCK_DGRAM)
self.port=port
self.clients = []
def run(self):
"Starten des Servers"
try: # versucht ...
self.bind(("",self.port)) # alle IP-Adressen auf Client-PORT
while True: # laeuft solange bis Tastaturabbruch
daten, client = self.recvfrom(256) # holt Daten und Adresstupel von Bindung
if PYTHON_NEW:
daten = str(daten,'UTF-8')
#bei Erstkontakt erfolgt keine Auswertung der Nachricht, sondern nur Anmeldung
if client not in self.clients:
self.clients.append(client)
nummer = self.clients.index(client)
self.senden_an("self.nummer="+str(nummer),client)
#self.senden_an_alle("print ('Spieler "+str(nummer)+" angemeldet.')")
#
# HIER WERDEN DIE DATEN ZENTRAL VERARBEITET
#
elif not daten: # kommt ein Leerstring...
break # wird Schleife beendet
elif daten == "!ende": # Signal zum Schliessen des Servers
self.senden_an_alle("!ende")
break # Schleife beenden
else:
self.senden_an_alle(daten)
except:
print ("Problem: Server laeuft nicht.")
finally:
print ("\nServer schliesst sich jetzt.")
self.close() # Verbindung schliessen
def senden_an_alle(self,nachricht):
for r in self.clients:
self.senden_an(nachricht,r)
def senden_an(self, nachricht, empfaenger):
if PYTHON_NEW:
nachricht = bytes(nachricht,'UTF-8')
self.sendto(nachricht,empfaenger)
##########################
class udpClientPlus(Thread):
"""Legt einen Client an. Der sendet einen Broadcast, wenn der von einem
Server empfangen wird, wird der Empfang bestaetigt und der Client am Server registriert.
Wenn es keine Antwort eines Servers gibt, wird ein Server als Thread angelegt."""
def __init__(self, benutzer, port =PORT, new = PYTHON_NEW):
Thread.__init__(self)
self.benutzer = benutzer #an diesen wird Nachricht weitergeleitet
self.port = port
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # AF_INET = IPv4, SOCK_DGRAM = UDP
self.s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1) # Broadcast ermoeglichen
#Testen, ob es schon einen Server gibt
try:
self.s.sendto("print('ich moechte mitspielen!')",
('255.255.255.255', port)) # sende Nachricht 'an alle' - in ausfuehrbarer Form, falls exec(nachricht), wird aber eh ignoriert
self.s.settimeout(2) # warte ein bisschen..
nachricht = self.s.recvfrom(64)[0]
if PYTHON_NEW:
nachricht = str(nachricht,'UTF-8')
self.s.settimeout(3000)
except: # reagiert auf Zeitueberschreitung
print ("Kein Server vorhanden - starte Server") # Rueckmeldung
server = udpServer(port) # Starten eines Servs als Thread
server.start()
self.s.setblocking(1) # nicht-blockierend
#dem server etwas Zeit lassen, damit er Anmeldung verarbeiten kann
from time import sleep
sleep(1)
#Erstanmeldung am (jetzt) laufenden Server
self.senden("print ('hallo neuer server')")
self.start()
def run(self):
"Hier lauscht der Client auf Nachrichten und leitet sie an den eigentlichen Benutzer weiter."
while True:
nachricht = self.s.recvfrom(128)[0]
if PYTHON_NEW:
nachricht = str(nachricht,'UTF-8')
if nachricht == "!ende":
print ("\nClient beendet.")
break
self.benutzer.empfangen(nachricht)
def senden(self,nachricht):
"Diese Methode nutzt der eigentliche Benutzer, um Nachrichten an den Server verschicken."
if PYTHON_NEW:
nachricht = bytes(nachricht,'UTF-8')
self.s.sendto(nachricht, ('255.255.255.255', self.port)) # versenden der Nachricht an Tupel(IP, PORT)
##########################
class Teilnehmer():
def __init__(self, port = PORT):
self.verbinder = udpClientPlus(self, port)
def empfangen(self, nachricht):
"""Diese Methode kann/soll durch eine Methode der Unterklasse ueberschrieben werden.
Standardmaessig wird eingegangene Nachricht unmittelbar als Code ausgefuehrt."""
try:
exec (nachricht)
except:
print ("Fehler beim Ausfuehren (exec) der Nachricht:")
print ("'"+nachricht+"'")
def senden(self,nachricht):
"Diese Methode wird von der Unterklasse nicht ueberschrieben, aber benutzt."
self.verbinder.senden(nachricht)
def beenden(self):
self.senden("!ende")