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()
###

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