[xmlrpc] Eine Art Event vom Server an den Client

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Linut
User
Beiträge: 2
Registriert: Sonntag 28. Januar 2007, 18:58
Wohnort: Riedstadt
Kontaktdaten:

Hallo python-Forum,

ich versuche gerade eine Client/Server-Lösung für unser kleines Hausnetzwerk zu entwickeln. Ziel ist es, den Server nur so lange wie nötig angeschaltet zu lassen.

Per Client wird der ServerPC geweckt (WOL). Sobald der Server(Python-Programm) gestartet ist, meldet sich der Client an. Bei der Anmeldung wird ein Client-Passwort, ein Username und ein "Timeout" übertragen. Der Server überprüft nun per Thread welcher User sein Timeout überschritten hat und löscht ihn aus der Liste. Ist die Liste leer, wird der Server heruntergefahren.

Ich habe nun ein größeres und ein kleineres Problem (abgesehen von vielen Kinderkrankheiten die ich aber erstmal nicht beachte...):
  • größer: Ich würde mir eine Art Event vom Server an den Client wünschen, um dem Client mitzuteilen, dass seine Zeit um ist.
  • kleiner: Meldung vom Server an den Client, dass er bereit ist (nach dem Hochfahren).
Meine Überlegungen:
Das kleinere Problem ist nicht zu lösen, da der Server ja nur auf "vorhandene" Clients reagieren kann.
Zum Größeren: Der Client löchert den Server zB alle paar Sekunden, ob er(Client) noch in der Liste des Servers vorhanden ist.

Ich habe erst vor kurzem mit Python begonnen. Und seit noch kürzerem mit Threads, seit also ein bisschen nachsichtig mit mir :D

Code: Alles auswählen

#!/usr/bin/python
## ServerScripts.py

from SimpleXMLRPCServer import SimpleXMLRPCServer
import time
from threading import Thread, Event
from socket import error
from SocketServer import TCPServer

class CheckServerStatus(Thread):

	def run(self):
		global userlist
		interval = 5
		time.sleep(10)

		while len(userlist) != 0:
			time.sleep(interval)
			
			tmplist = userlist.copy()

			print "#### Check Server Status ####"
			
			for user in tmplist:
				print "check\t%s\t%i\t%i" % (user, (time.time() - userlist[user].timestamp), (int(userlist[user].timeout)*60))
				interval = 5
				if  ((int(userlist[user].timeout) * 60) - (time.time() - userlist[user].timestamp)) < 5:
					difference = (int(userlist[user].timeout) * 60) - (time.time() - userlist[user].timestamp)
					time.sleep(difference)
					print "del\t%s\t%i\t%i" % (user, (time.time() - userlist[user].timestamp), (int(userlist[user].timeout) * 60))
					del userlist[user]
					interval = 5 - difference
	
			del tmplist

		if len(userlist) == 0:												#Wenn kein user mehr angemeldet ist, shutdown einleiten
			print "SHUTDOWN"
	

class SSUser:
	def __init__(self,password,timeout):
		self.password = password
		self.timestamp = time.time() 
		self.timeout = timeout
	def __repr__(self):
		return repr(self.timestamp)

userlist = {}
SERVER_PW = ''

def AddUser(user,password,server_pw,timeout):
	global userlist

	if not userlist.has_key(user):											#Ueberpruefen ob ein solcher user schon existiert
		userlist[user] = SSUser(password,timeout)								#falls nicht, neuen Key mit class SSUser anlegen
		return 100												#"all right"
	else:
		return 101												#"user already logged in"

def DelUser(user,password,server_pw):
	global userlist

	if userlist.has_key(user):											#Ueberpruefen ob ein solcher user exisitert
		if server_pw == SERVER_PW:										#Das ServerPassword ueberpruefen
			if password == userlist[user].password:								#Das userPassword ueberpruefen
				del userlist[user]									#Falls beides stimmt, user aus _____ loeschen
				return 100										#"all right"
			else:
				return 103										#"wrong user password"
		else:
			return 102											#"wrong server password"
	else:
		return 104												#"user not in list"

try:
	# Create server
	TCPServer.allow_reuse_address = True
	server = SimpleXMLRPCServer(("localhost", 8000))
	server.register_introspection_functions()

	server.register_function(AddUser)
	server.register_function(DelUser)
	server.register_function(CheckServerStatus)

	# Run the server's main loops
	t = CheckServerStatus().start()
	server.serve_forever()
except error, v:
	print "ERROR", v

Code: Alles auswählen

#!/usr/bin/python
## ServerScriptsClient.py

#import xmlrpclib
import xmlrpclib
import wolpython
from socket import error
from time import sleep

def StartServer(ip, mac, name, pw, server_pw, timeout):
	global s
	ServerNotReady = 1
	Try = 1
	
	print "Wake up Server with Mac " + mac
	wolpython.wol(mac)

	print "Trying to connect to " + ip
	s = xmlrpclib.ServerProxy('http://localhost:8000')
	print s
	
	while ((ServerNotReady) and (Try < 11)):
		try:
			result = s.AddUser(name,pw,server_pw,timeout)
			ServerNotReady = 0
		except error, v:
			result = 0
			sleep(5)
			print "Try: ", Try, " ERROR", v
			Try = Try + 1

	return result
	

def StopServer(name, pw):
	global s

	return s.DelUser(name,pw,'')
[url=http://www.luggg.de/]LUG Gross-Gerau[/url]
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Du könntest über einen UDP-Socket auf Ansagen des Servers lauschen. Dabei kann dieser dem Client über Unicast mitteilen, wenn dessen Zeit um ist, und einen Broadcast senden, auf den alle interessierten Clients im (Sub-)Netz lauschen können.
cyp++
User
Beiträge: 69
Registriert: Freitag 22. September 2006, 13:54

Code: Alles auswählen

global
das ist zu vermeiden.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Linut hat geschrieben:Client/Server-Lösung für unser kleines Hausnetzwerk
Hallo Linut!

Bei einem kleinen oder größeren Hausnetzwerk kann ich mir schlimmeres vorstellen, als ein kleines Programm, das alle 10 sec. mal versucht den Server etwas zu fragen.

Ich persönlich würde bei XMLRPC bleiben und einfach alle 10 sec. von den Clients aus eine XMLRPC-Anfrage an den Server starten.

Wenn du ein Timeout einbaust:

Code: Alles auswählen

import socket
socket.setdefaulttimeout(3) # Timeout auf 3 sec. setzen
dann sollte es auch kein Problem sein, wenn der Server mal nicht erreichbar ist.

So brauchst du keine Verbindung vom Server zum Client aufbauen und kompliziert ist es auch nicht.

Wenn du noch fragen hast -- einfach hier melden.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

gerold, was sprich denn gegen UDP?

Effizienter wäre es sicher. Einfach auch. :wink:
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

veers hat geschrieben:was sprich denn gegen UDP? Effizienter wäre es sicher. Einfach auch. :wink:
Hallo veers!

Es spricht nichts, absolut gar nichts gegen UDP. Aber da sich der OP ja schon in XMLRPC eingearbeitet hat, glaube ich dass er/sie sich leichter mit einer einfachen XMLRPC-Lösung tut.

:wink: Und was kann einfacher als das hier: http://www.python-forum.de/topic-5478.html sein? Eine voll funktionsfähige Client-Server-Lösung mit so wenig Zeilen und so wenig Kopfzerbrechen... :twisted:

Der Vorteil von XMLRPC ist der, dass ich mir kein Kopfzerbrechen um das Verpacken der Daten machen muss. Einfach eine Funktion mit ein paar Parametern aufrufen und auf das Ergebnis warten. Fertig.

Das sind die Gründe, weshalb ich XMLRPC vorschlage -- und zwar für alles, was nicht zeitkritisch ist und wo nicht Megabytes an Daten übertragen werden müssen.

:roll: ...du hast gefragt.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Linut
User
Beiträge: 2
Registriert: Sonntag 28. Januar 2007, 18:58
Wohnort: Riedstadt
Kontaktdaten:

Vielen Dank erstmal für eure Antworten!
gerold hat geschrieben:Bei einem kleinen oder größeren Hausnetzwerk kann ich mir schlimmeres vorstellen, als ein kleines Programm, das alle 10 sec. mal versucht den Server etwas zu fragen.
Das ist natürlich auch war. Ich denke ich werde, faul wie ich bin, erstmal diesen Weg gehen und evtl. später eine andere Möglichkeit (werde dann mal auf euch zurück kommen Y0Gi/veers :)) versuchen. (Ich habe ja nur eine Bestätigung von jemand anderem gebraucht :D)
cyp++ hat geschrieben:

Code: Alles auswählen

global
das ist zu vermeiden.
Ok. Dann musst du mir vielleicht einen Tipp geben, wie ich das anstellen muss. Im Server habe ich ja die "userlist" global um wie in einer Datenbank User hinzuzufügen, zu prüfen oder zu löschen. Ich kann die userlist ja nicht als an die Funktion übergeben, da diese ja vom Client aufgerufen wird.. oder habe ich da etwas missverstanden.
[url=http://www.luggg.de/]LUG Gross-Gerau[/url]
cyp++
User
Beiträge: 69
Registriert: Freitag 22. September 2006, 13:54

Hab deinen Code kurz überflogen, userlist ist in der Klasse eine andere userlist? Du kannst einfach um auf die userlist innerhalb einer Klasse zu zu greifen es als Klassen-Attribut initialisieren o.Ä.

Code: Alles auswählen

class DummyClass(object):
    userlist = [] # Klassen-Attribut
    
    def foo(self):
        # mehrere Punkte sind zu vermeiden btw.
        self.userlist.Append("user") # hänge "user" an userlist.
                                                
    def returnMethod(self):
    """
    Für den Fall, dass du die userlist an andere Funktionen oderso  übergeben willst.
"""
        return self.userlist
Oder mit Vvererbung?!

Code: Alles auswählen

class DummyClass1(DummyClass): # erbt von der Oberklasse
    def foo1(self):
       print "foo1"
Antworten