ThreadingTCPServer ( für ein Online-RPG )

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
Kolazomai
User
Beiträge: 33
Registriert: Donnerstag 16. Februar 2006, 15:05
Kontaktdaten:

Dienstag 21. März 2006, 16:48

Hi,

irgendwann hab ich mal gefragt, wie ein ThreadingTCPServer funktioniert. Nachdem mich irgendein netter User aufgeklärt hat, hab ich mit einem Kumpel zusammen angefangen, ein Online-RPG zu entwickeln. Ich schreib den Server, mein Freund den Clienten ( mit Visual Basic ).

Ich hab jetzt ein Problem: Mein Freund sendet mir sehr schnell hintereinander "onl" "req" und "araHeim" ; aber bei mir wird dann angezeigt: "onl" "reqaraHeim": D.h. das "req" und das "araHeim" wird zu 1 Nachricht zusammengefasst. Ich hab jetzt schon ein bisschen mit Beispielprogrammen rumprobiert, woran das liegen kann und bin zu dem Schluss gekommen, dass es wohl mit dem .recv(<zahl>) zusammenhängt.

Das Programm ist noch nicht fertig ( pvp fehlt u.s.w. ) , deshalb hab ichs mal in CodeSnippets reingeschoben.

Hier mal der Source:

Code: Alles auswählen

# Name des RPGs
# Coded by Kolazomai
# ICQ: 329-573-284
# Published under GPL
#####################################
### Name des RPGs                 ###
#####################################

print "###################################"
print "### Name des RPGs               ###"
print "### Server Edition              ###"
print "###################################"
print "Starting Server now ..."

### import ###
import SocketServer,os
from SocketServer import ThreadingTCPServer
from time import gmtime, strftime
###






### Log ###
logfile = "/home/cordel/Heldensagen.log"
log = open(logfile,"w")
###





### Variables ###
port = 1337 #port
clients = {} # {ip:client,...}
ips = [] # ips
message_pot = {} # messages , i dont know whether i need it
messages = [] # same
group_all = [] # w00t
message_all = "" # ...
Login = False # ...
gibts = False # ...
all_users = {} # ... I dont need that any more, cause of users_data
all_users_split = [] # ...
locals_users = {"Heim":[],
                "Wald":[],
                "Gebirge":[],
                "Tropfsteinhoehle":[],
                "Vulkan":[],
                "Untoten-Gruft":[],
                "Verlassene Zwergenmine":[],
                "Troll-Lagerstaetten":[],
                "Hauptstadt Gut":[],
                "Hauptstadt Boese":[]} # {location:[name1,name2,name3],...}
###
# This is a very powerful Variable
# It will look like that:
# {Name:{Name:<name>,Race:<race>,..},Name2:{...}}
# I do have just to call
# users_data[Name][<info>] and i get what i want
users_data = {}
# Values:
# Name,Race,Level,Mana,current Mana,Hp,current Hp,
# Staerke,Geschick,Avaibility,Location
###

######



### all players ###
def all_players():
    global all_users_split
    # Why do i need this Variable ?
    # It's cause of that get_char_info
    # Oh god, this prog has a bad performance ...
    all_players_file = file("/home/cordel/rpg/all_users.txt","r")
    all_users_read = all_players_file.read()
    all_players_file.close()
    all_users_split = all_users_read.split("\n")
###





### class Main ###
class main_:
    def __init__(self):
        pass

###


    def login(self,data):
        global Login
        login_data = data.split('!')
        ### Get User's Data ###
        self.users_data_file = open('/home/cordel/rpg/users/'
                                    +str(login_data[0])+'.txt','r')
        self.users_data = self.users_data_file.read()
        self.users_data = self.users_data.split('\n')
        self.users_data_file.close()
        ###
        if self.users_data[1] == login_data[1]:
            print_("Server: Login Correct :>")
            Login = True
        else:
            print_("Server: Login Incorrect!")
            Login = False

###

    def new(self,data):
        global gibts
        self.x = data.split("!")
        try:
            #File exist?
            os.stat("/home/cordel/rpg/users/"
                        +str(self.x[0])+".txt")
            gibts = True
        except OSError:
            # no it doesn't
            self.a = open("/home/cordel/rpg/users/"
                          +str(self.x[0])+".txt","w")
            self.a.write(str(self.x[0])+'\n')#1.Name
            self.a.write(str(self.x[1])+'\n')#2.Pass
            self.a.write(str(self.x[2])+'\n')#3.Race
            self.a.write("1"+"\n")#4.Level
            self.a.write("80"+"\n")#5.Mana
            self.a.write("10"+"\n")#6.Staerke
            self.a.write("6"+"\n")#7.Geschick
            self.a.write("100"+"\n")#8.Leben , HP
            self.a.write("100"+"\n")#9.current HP
            self.a.write("80"+"\n")#10.current Mana
            self.a.close()

            
            # Add this player to all_players#
            all_players_file = file("/home/cordel/rpg/all_users.txt","a")
            all_players_file.write(str(self.x[0])+"\n")#Player's name
            all_players_file.close()
            #

            # Get new all_players_list #
            all_players()
            #

###


    def get_char_info(self,name,ip):
        global all_users,users_data
        self.users_data_file = open('/home/cordel/rpg/users/'
                                    +str(name)+'.txt','r')
        self.users_data = self.users_data_file.read()
        self.users_data = self.users_data.split('\n')
        self.users_data_file.close()
        ##############################################################
        # What i do now:                                             #
        # there is all_users                                         #
        # I will pick up the logined user                            #
        # and make a new dic for him                                 #
        # {"Name":"Name",<datas>}                                    #
        # So all_names will look like that:                          #
        # [<ip>:{"name":"Kolazomai","race":"Human",...},<ip>:{...}]  #
        # then I only have to call all_names[client][<info>]         #
        # and i get what i want                                      #
        ##############################################################
        # Now i will try to fetch all character-infos #
        # 1.Name
        # 2.Pass
        # 3.Race
        # 4.Level
        # 5.Mana
        # 6.current Mana
        # 7.HP
        # 8.current HP
        # 9.Staerke
        # 10.Geschick

        # I think, i dont need all_users, cause users_data is the same ...
        all_users[ip] = {"NAME":str(self.users_data[0]),
                         "PASS":str(self.users_data[1]),
                         "RACE":str(self.users_data[2]),
                         "LEVEL":str(self.users_data[3]),
                         "MANA":str(self.users_data[4]),
                         "STAERKE":str(self.users_data[5]),
                         "GESCHICK":str(self.users_data[6]),
                         "LEBEN":str(self.users_data[7]),
                         "CURRENT_LEBEN":str(self.users_data[8]),
                         "CURRENT_MANA":str(self.users_data[9])}

        
        # Now i add it to my powerful users_data - variable
        users_data[name] = {"NAME":str(self.users_data[0]),
                            "RACE":str(self.users_data[2]),
                            "LEVEL":str(self.users_data[3]),
                            "MANA":str(self.users_data[4]),
                            "STAERKE":str(self.users_data[5]),
                            "GESCHICK":str(self.users_data[6]),
                            "LEBEN":str(self.users_data[7]),
                            "CURRENT_LEBEN":str(self.users_data[8]),
                            "CURRENT_MANA":str(self.users_data[9]),
                            "LOCATION":"Heim",
                            "AVAI":0} # short form of Avaibility


        # puhh, hard job xD #

        

###


### def print_ ###
def print_(it):
    log.write(str(it)+"\n")
    print it

###


### def Player Versus Player ###
class pvp:
    def __init__(self):
        pass
    

###




### Setting the Server-Routine ###
class handling(SocketServer.StreamRequestHandler):
	def handle(self):
            global message_pot,clients,log,Login,ips,messages,gibts
            global group_all,message_all,users_data,locals_users
            client,address = self.client_address
            print_(str(client)+" is here!")
            main = main_()
            while 1:
                data = self.request.recv(1000)
                if client in clients:
                    print_(str(clients[client])+"["+str(client)+"]"+
                           " said: "+str(data)
                           +" ["
                           +strftime("%a, %d %b %Y %H:%M:%S",gmtime())
                           +"]")
                else:
                    print_(str(client)+" said: "+str(data)
                           +" ["
                           +strftime("%a, %d %b %Y %H:%M:%S",gmtime())
                           +"]")


                
                if data[0:3] == "log":
                    #logUser!Pass!Race
                    main.login(data[3:])
                    if Login == True:
                        aa = data[3:].split("!")
                        clients[client] = aa[0]
                        print client,"is now also known as",clients[client]
                        ips += [client]
                        self.request.send(clients[client]+
                                          "!pra"+
                                          "Server: Login erfolgreich!")
                        main.get_char_info(clients[client],client)
                        # Add this user to the Home-Location
                        locals_users["Heim"].append(clients[client])
                    Login = False # nur zur Sicherheit


                
                elif data[0:3] == "msg":
                    x = data.split('!')
                    #msg!empfaenger!absender!nachricht
                    empfaenger = x[1]
                    absender = x[2]
                    nachricht = x[3]
                    #<Empfaenger>!msg<Nachricht>!<Absender>
                    if empfaenger in messages:
                        self.request.send(str(absender)+"!"+"msg"
                                          +str(empfaenger)
                                          +"did not receive a previous msg yet"
                                          +"!Server")

                    
                    elif empfaenger <> "all":
                        #the message
                        message_pot[empfaenger] = ( str(empfaenger)+"!"
                                                    +"msg"+str(nachricht)+"!"
                                                    +str(absender) )
                        # add empfaenger to the list
                        messages += [empfaenger]

                    
                    elif empfaenger == "all":
                        # message to all
                        # What i do now:
                        # Add all online Users to group_all
                        # Then create a message_all
                        # If a user req now
                        # I will proove,whether he is in group_all
                        # if yes, i will sent him the message_all
                        # and remove him from group_all
                        # if no, nothing happens
                        # The Problem is, that all guys have to req
                        # till its possible again to send a generall msg
                        if group_all == []:
                            la = []
                            for x in ips:
                                la += [clients[x]]
                            group_all += la
                            message_all =  ( str(empfaenger)+"!"
                                             +"msg"+str(nachricht)+"!"
                                             +str(absender) )
                        else:
                            self.request.send(str(absender)+"!"+"msg"
                                              +"Can't send a msg"
                                              +" to all at the moment"
                                              +"!Server")


                
                elif data[0:3] == "req":
                    #req
                    #for chat

                    
                    if clients[client] in messages:
                        print message_pot
                        #remove the empfaenger
                        messages.remove(clients[client])
                        #messagepop
                        self.request.send(str(message_pot.pop(clients[client])))

                    
                    if clients[client] in group_all:
                        self.request.send(message_all)
                        group_all.remove(clients[client])

                    
                elif data[0:3] == "new":
                    #newUser!Pass!Race
                    main.new(data[3:])
                    fuck_you = data[3:].split("!")
                    # I should work with
                    # if user in all_users.txt: ...
                    if gibts == True:
                        # Account existing allready
                        # editieren ------> V V V V V V V V V V V V V V V
                        self.request.send(str(fuck_you[0])+"!praServer:"+
                                          " Account does allready exist!")
                        gibts = False
                    else:
                        self.request.send(str(fuck_you[0])+"!praServer:"+
                                          " Neuer Benutzer angelegt!")


                
                elif data == "quit":
                    quit_()
                    break



                
                elif data[0:3] == "onl":
                    #onl
                    #Send back who's online
                    send_it = "all!onlall!"
                    for x in ips:
                        if x <> client:
                            send_it += str(clients[x])+"!" # returns the Names
                    send_it += "$"
                    self.request.send(send_it)# send the data


                
                elif data == "save_log":
                    #Save the log and open it again!
                    log.close()
                    log = open(logfile,"a")
                    quit_()
                    break





                elif data == "akt":
                    #<Empfaenger>!akt<Level>!<Leben im moment>
                    #!<Leben gesamt>!<Mana im Moment>!<Mana gesamt>
                    #!<Geschicklichkeit>!<Staerke>!$

                    self.request.send(str(clients[client])+"!"+
                                      "akt"+
                                      str(all_users[client]["LEVEL"])+"!"+
                                      str(all_users[client]["CURRENT_LEBEN"])+"!"+
                                      str(all_users[client]["LEBEN"])+"!"+
                                      str(all_users[client]["CURRENT_MANA"])+"!"+
                                      str(all_users[client]["MANA"])+"!"+
                                      str(all_users[client]["GESCHICK"])+"!"+
                                      str(all_users[client]["STAERKE"])+"!"+
                                      "$")

                    


                elif data[0:3] == "sav":
                    #savName!Pass!Rasse
                    #!Level!Mana!Staerke!
                    #Geschick!Leben!Leben im moment!Mana im moment
                    x = data[3:].split("!")
                    users_file_ = file("/home/cordel/rpg/users/"+
                                       str(clients[client])+".txt","w")
                    users_file_.write(str(x[0])+"\n")#Name
                    users_file_.write(str(x[1])+"\n")#Password
                    users_file_.write(str(x[2])+"\n")#Rasse
                    users_file_.write(str(x[3])+"\n")#Level
                    users_file_.write(str(x[4])+"\n")#Mana
                    users_file_.write(str(x[5])+"\n")#Staerke
                    users_file_.write(str(x[6])+"\n")#Geschick
                    users_file_.write(str(x[7])+"\n")#Leben
                    users_file_.write(str(x[8])+"\n")#current leben
                    users_file_.write(str(x[9])+"\n")#current mana
                    # lots of writing :o
                    
                    users_file_.close()
                    main.get_char_info(clients[client],client)



                
                elif data[0:3] == "ara":
                    # ara = actualise place of residence
                    # syntax: araLocality
                    # example: araWood
                    # ------------------
                    # i send back: ( in 1 string )
                    # <Empfaenger>!ara<Spielerinmeinemgebiet1(name)>?
                    #<Spielerinmeimemgebiet1(verfuegbarkeit)!
                    #<spielerinmeinemgebiet2(name)>?
                    #<Spielerinmeimemgebiet2(verfuegbarkeit)!$
                    # ---------------
                    # Localities
                    # Heim ::: 1 
                    # Wald ::: 2 
                    # Gebirge ::: 3 
                    # Tropfsteinhoehle ::: 4 
                    # Vulkan ::: 5 
                    # Untoten-Gruft ::: 6 
                    # Verlassene Zwergmine ::: 7 
                    # Troll-Lagerstaetten ::: 8 
                    # Hauptstadt Gut ::: 9 
                    # Hauptstadt Boese ::: 10
                    #########################


                    # This is all users in the specified locality
                    teh_clients = locals_users[data[3:]]
                    message_ara = (str(clients[client])+"!"+
                                   "ara")
                    for x in range(len(teh_clients)):
                        # I add to message_ara
                        # the name of the boyz in the locations ( teh_clients )
                        # and then the available key in the users_data
                        if teh_clients[x] <> clients[client]:
                            message_ara += (str(teh_clients[x])+"?"+
                                            str(users_data[teh_clients[x]]["AVAI"])+
                                            "!")
                    
                    message_ara += "Some_Player?0!$" # final letter :-)

                    # Now send it ;-) #
                    print message_ara
                    self.request.send(message_ara)
                                      



                elif data[0:3] == "soa":
                    # soa = *S*-tatus *O*-f *A*-vailability
                    # 0 = available
                    # 1 = not available
                    users_data[clients[client]]["AVAI"] = data[4]




                elif data[0:3] == "apr":
                    x = data[3:].split("!")
                    # aprNewLocation!OldLocation
                    # user changes location
                    try:
                        # remove user of the location
                        locals_users[x[1]].remove(clients[client])
                    except:
                        pass
                    # add this user to the location
                    locals_users[x[0]].append(clients[client])

                    # change the users_data -variable
                    users_data[clients[client]]["LOCATION"] = x[0]
                


                elif data[0:3] == "pvp":
                    a = pvp
                    print "pvp"



              

                
                else:
                    quit_()
                    break

                    

###



### def quit_ ###
def quit_():
    #.pop removes the name
    try:
        print_(str(clients.pop(client))+"["+str(client)+"]"+
               " left!")
    except:
        pass
    #remove the ip
    try:
        ips.remove(client)
    except:
        pass
    
    # remove him from Location
    try:
        locals_users[users_data[clients[client]]["LOCATION"]].remove(clients
                                                                     [client])
    except:
        pass
    try:
        del users_data[clients[client]]
    except:
        pass
    try:
        group_all.remove(clients[client])
    except:
        pass

###






### Starting the Server ###
server = ThreadingTCPServer(("",port), handling)
server.serve_forever()
###
Ich bin mir bewusst, dass ich teilweise ziemlich unschön programmiert habe ( die globals, die vielen try-s, die str() u.s.w. ) , aber das soll jetzt nicht das Hauptthema hier werden ( würde mich aber trotzdem über Verbesserungsvorschläge freuen ). Einige Variablen sind auch überflüssig, muss ich dann noch ändern. Ausserdem ist das Englisch in den Comments nicht perfekt, aber ich verstehs ;)

Nochmal:
Warum bekomme ich anstatt den getrennten 3 Nachrichten "onl" "req" und "ara*" , "onl" "reqara*" ( * = Platzhalter für Ort ) ?
Hängt das mit .recv(int) zusammen oder mit Winsock ?

Was haltet ihr von dem Vorschlag, dass mir zuerst die Länge des Zu-Schickenden gesendet wird und ich dann mein .recv darauf abstimme, wenn es daran liegen sollte ?

Danke für die Bemühungen, und dass ihr euch durch meinen Sourcecode gewühlt habt :)

Edit: http://waldkautz.wa.funpic.de/ServerV1.0.py ist der Source-Code zum runterladen.

und: Hat gerade komischerweise auch mal funktioniert ?!

Edit2: Wenn er das "onl" weglässt, funktioniert es scheinbar!

Edit3: Wie ich auf den Schluss komme, dass es mit .recv(<int>) zu tun hat ? Hab einen kleinen Server geschrieben, der 1 Verbindung annimmt, und dann auf Nachrichten wartet und die ausgibt. Server gestartet, Clienten geschrieben, der in einer while-Schleife "aa" sendet, bis ich unterbreche ( mit strg+c ) ; Wenn .recv(1000) war, hat er manchmal ( ca 30 % ) nicht aa ausgegeben ( als empfangenes ), sondern "aaaa" oder "aaaaaa". Daraus schlussfolgere ich, dass es mit der Grösse von .recv zu tun hat, weil ich danach .recv auf 10 erniedrigt habe und nur noch "aa" ankam.

Mfg,

Kolazomai
Zuletzt geändert von Kolazomai am Dienstag 21. März 2006, 17:18, insgesamt 1-mal geändert.
Python 47
User
Beiträge: 574
Registriert: Samstag 17. September 2005, 21:04

Dienstag 21. März 2006, 17:06

Warum importierst du am anfang 2x SocketServer?
mfg

Thomas :-)
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Dienstag 21. März 2006, 17:07

Ist zwar halb off-topic, aber versuch mal deinem Freund Python näherzubringen. Ich bin sicher, er wird es nicht bereuen.
Benutzeravatar
Kolazomai
User
Beiträge: 33
Registriert: Donnerstag 16. Februar 2006, 15:05
Kontaktdaten:

Dienstag 21. März 2006, 17:10

@ Python Master 47:

Fühl mich sicherer damit. Brauch ja noch irgendson Schmarrn von der SocketServer-Library.

@ Joghurt:

Hab ich schon probiert ;) Der bleibt lieber bei seinem VB und tut Python als "primitive" Sprache ab ^^ Naja, will mich mit ihm ned streiten :P

Mfg,

Kolazomai
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Dienstag 21. März 2006, 17:15

Kolazomai hat geschrieben:Der bleibt lieber bei seinem VB und tut Python als "primitive" Sprache ab
LOL. Ich glaube, das hänge ich mir übers Bett :)
Python 47
User
Beiträge: 574
Registriert: Samstag 17. September 2005, 21:04

Dienstag 21. März 2006, 17:41

[quote="Kolazomai"]@ Python Master 47:

Fühl mich sicherer damit. Brauch ja noch irgendson Schmarrn von der SocketServer-Library.
/quote]

In dem Fall wäre aber das from SocketServer import ThreadingTCPServer überflüssig!
mfg

Thomas :-)
Benutzeravatar
Kolazomai
User
Beiträge: 33
Registriert: Donnerstag 16. Februar 2006, 15:05
Kontaktdaten:

Dienstag 21. März 2006, 17:46

Python Master 47 hat geschrieben:
In dem Fall wäre aber das from SocketServer import ThreadingTCPServer überflüssig!
Nein, gibt einen Fehler, wenn ich es nicht dazuschreib! Kannste ja mal ausprobieren...

Btw... kommt mal zum eigentlichen Problem pls :D

Mfg,

Kolazomai
Benutzeravatar
Kolazomai
User
Beiträge: 33
Registriert: Donnerstag 16. Februar 2006, 15:05
Kontaktdaten:

Dienstag 21. März 2006, 19:45

Hi,

so, es geht immer noch ned :S

Wir haben es jetzt so gelöst, dass immer ein Pack von Befehlen kommt.

Aber es gibt schon wieder ein neues Problem:

Es werden 2 Nachrichten wieder zu 1 zusammengfasst und zurückgesendet.

Hier der Source.

Was tun ?!

Mfg,

Kolazomai
Antworten