我按如下方式定义服务器类(编辑):
class server:
def __init__( self, ip = "", port = 0 ):
self.SetAddress( ip, port )
self.__players = []
def __SetSocket( self, blocking = 0, queue = 4 ):
self.__listener = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
self.__listener.bind( self.GetAddress() )
self.__listener.setblocking( blocking )
self.__listener.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
self.__listener.listen( queue )
self.__listener.settimeout( 5 )
self.__read, self.__write, self.__error = [ self.__listener ], [], []
def __AddClient( self, source ):
c, a = source.accept()
c.settimeout( 5 )
self.__read.append( c )
send( c, "Welcome!" )
print a, "Connection established"
return
def __AddPlayer( self, source, nick ):
if len( self.__players ) == 4:
send( source, ('Error', "4 players already connected.") )
self.__read.remove( source )
return
self.__players.append( nick )
send( source, ('ID', self.__players.index(nick)) )
def __RemovePlayer( self, source, gamer_id ):
self.__players.pop( gamer_id )
self.__read.remove( source )
source.close()
def __Connect( self ):
joining = True
while joining:
r, w, x = select( self.__read, self.__write, self.__error, 0 )
for s in r:
if s is self.__listener:
self.__AddClient( s )
else:
data = receive( s )
if data:
print data, s.getpeername()
if self.__MaintainPlayers( s, data ):
pass
if len( self.__players ) == 4:
joining = False
return
def __MaintainPlayers( self, source, data ):
if data[0] == "Nick":
self.__AddPlayer( source, data[1] )
return True
elif data[0] == "Quit":
self.__RemovePlayer( source, data[1] )
return True
return False
def run( self ):
self.__SetSocket( 1, 4 )
print "Waiting for players."
self.__Connect()
其中,发送和接收功能如下:
def send( channel, message ):
try:
channel.send( json.dumps(message) )
return True
except OSError as e:
print e
return False
def receive( channel, packet_size = 64 ):
try:
data = channel.recv( int(packet_size) )
if not data:
return None
print data
return json.loads( data.strip() )
except OSError as e:
print e
return False
client
类很简单(编辑):
class client:
def __init__( self, name, srvIP, srvPort ):
ip = socket.gethostbyname( socket.gethostname() )
self.__server_address = self.__server_ip, self.__server_port = srvIP, srvPort
self.__ID = None
self.__nick = name
self.__SetListener()
def __SetListener( self ):
self.__listener = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
self.__listener.settimeout( 5 )
try:
self.__listener.connect( self.__server_address )
except Exception, e:
print "Unable to connect", e
raise e
print "Connected to %s:%d." % self.__server_address
send( self.__listener, ("Nick", self.__nick) )
def run( self ):
self.__read, self.__write, self.__error = [ self.__listener ], [], []
while True:
r, w, x = select( self.__read, self.__write, self.__error, 0 )
for f in r:
if f is self.__listener:
data = receive( f )
if data:
print data
if data[0] == "ID":
self.__ID = int( data[1] )
# More conditions
发生的情况是,我的客户端同时对receive
和Welcome
消息ID
。这会引发异常,如下所示:
$ client.py
Connected to 10.109.1.92:7777.
"Welcome!"["ID", 0]
Traceback (most recent call last):
File "%PATH%\client.py", line 115, in <module>
c.run()
File "%PATH%\client.py", line 86, in run
data = receive( f )
File "%PATH%\connect.py", line 17, in receive
return loads( data.strip() )
File "%PYTHON%\lib\json\__init__.py", line 338, in loads
return _default_decoder.decode(s)
File "%PYTHON%\lib\json\decoder.py", line 369, in decode
raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 1 column 28 - line 1 column 37 (char 27 - 36)
也就是说,客户端收到以下字符串:
"Welcome!"["ID", 0]
会在json.loads
中引发错误。
是否有一些方法可以在消息之间引入任何类型的延迟?
答案 0 :(得分:4)
您需要在发送邮件时添加邮件的大小,以便在收到邮件时,您只能返回该邮件,并知道您拥有整条邮件。套接字模块中没有任何内容可以执行此操作,因为它们只是实现了低级管道。
当您使用消息的大小发送消息前缀时:
def send( channel, message ):
try:
msg = json.dumps(message)
channel.send(struct.pack("i", len(msg)) + msg)
return True
except OSError as e:
print e
return False
当您收到消息时,首先检索大小,然后重复调用recv
,直到您收到整条消息。
def receive( channel ):
try:
size = struct.unpack("i", channel.recv(struct.calcsize("i")))[0]
data = ""
while len(data) < size:
msg = channel.recv(size - len(data))
if not msg:
return None
data += msg
print data
return json.loads( data.strip() )
except OSError as e:
print e
return False
答案 1 :(得分:3)
或者,如果您可以保证您的消息不包含特定字符(例如空字节),您可以将其附加到您的字符串,然后服务器端,将该字符串拆分为空字符:
客户端:
socket.sendall(json_string + '\0')
服务器:
recv_buffer = ""
while True:
data = connection.recv(128)
recv_buffer = recv_buffer + data
strings = recv_buffer.split('\0')
for s in strings[:-1]:
print("Received: %s" % s)
recv_buffer = strings[-1]