我正在研究2人遊戲(類似於俄羅斯方塊)的網絡部分,我試圖將遊戲網格從客戶端傳遞到服務器,反之亦然。然而,當我嘗試使用發送(網格)時,我得到一個TypeError:send()參數1必須是字符串或只讀緩衝區,而不是實例。發送數據作爲實例使用Python套接字
有沒有辦法繞過這個,還是我必須將我的網格實例轉換成一個字符串,然後從另一端解釋它?提前致謝!
我正在研究2人遊戲(類似於俄羅斯方塊)的網絡部分,我試圖將遊戲網格從客戶端傳遞到服務器,反之亦然。然而,當我嘗試使用發送(網格)時,我得到一個TypeError:send()參數1必須是字符串或只讀緩衝區,而不是實例。發送數據作爲實例使用Python套接字
有沒有辦法繞過這個,還是我必須將我的網格實例轉換成一個字符串,然後從另一端解釋它?提前致謝!
調查數據序列化:pickle。它會在發送端執行數據序列化(將會話轉換爲字符串),然後在接收端進行反序列化(即轉換回數據結構)。
除非您完全控制客戶端和服務器軟件,否則您應該猶豫使用pickle來回傳輸數據。如果你確定你不知道的數據是可信的,那麼Pickle是非常棒的,但如果它可能被篡改,它是不安全的。請參閱Why Python Pickle is Insecure或pickle module documentation中的安全警告建議。
對於格式化數據來回發送來說,JSON是一個很好的選擇; XML是好的,YAML非常好。簡單的消息傳遞格式可能是發送消息數據的大小,分隔符(CRLF
或\r\n
是常見的),然後是消息數據。
如果使用JSON,你就必須要麼堅持使用json
模塊知道如何編碼/解碼,或寫JSONEncoder
和JSONDecoder
子類來處理你感興趣的類型的對象。
下面是一個可以運行的概念JSON證明(不知道它是否可以在Windows上運行)。只需在兩個終端中的每一個終端上運行,輸入一個,然後顯示在另一個終端中。
import socket
import select
import sys
import json
CRLF = '\r\n'
class MalformedMessage(Exception): pass
class ConnectionClosed(Exception): pass
def read_exactly(sock, buflen):
data = ''
while len(data) != buflen:
data += sock.recv(buflen - len(data))
return data
def peek(sock, buflen):
data = sock.recv(buflen, socket.MSG_PEEK)
return data
def socket_send(sock, obj):
data = json.dumps(obj)
size = len(data)
sock.sendall('%i%s%s' % (size, CRLF, data))
def socket_recv(sock):
peekdata = peek(sock, 1024)
if peekdata == '':
raise ConnectionClosed
sizepos = peekdata.find(CRLF)
if sizepos == -1:
raise MalformedMessage('Did not find CRLF in message %r' % peekdata)
sizedata = read_exactly(sock, sizepos)
read_exactly(sock, len(CRLF))
try:
size = int(sizedata)
except ValueError:
raise MalformedMessage(
'size data %r could not be converted to an int' % sizedata)
data = read_exactly(sock, size)
return json.loads(data)
if __name__ == '__main__':
netloc = ('', 7777)
try:
servsock = socket.socket()
servsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
servsock.bind(netloc)
servsock.listen(5)
sock, _ = servsock.accept()
except socket.error:
sock = socket.socket()
sock.connect(netloc)
try:
while True:
r_ok, _, _ = select.select([sys.stdin, sock], [], [])
for fd in r_ok:
if fd == sys.stdin:
obj = eval(fd.readline().strip())
socket_send(sock, obj)
elif fd == sock:
obj = socket_recv(sock)
print repr(obj)
except (KeyboardInterrupt, ConnectionClosed):
pass
finally:
print '\nexiting...'