2010-05-01 77 views
1

我正在研究2人游戏(类似于俄罗斯方块)的网络部分,我试图将游戏网格从客户端传递到服务器,反之亦然。然而,当我尝试使用发送(网格)时,我得到一个TypeError:send()参数1必须是字符串或只读缓冲区,而不是实例。发送数据作为实例使用Python套接字

有没有办法绕过这个,还是我必须将我的网格实例转换成一个字符串,然后从另一端解释它?提前致谢!

回答

1

调查数据序列化:pickle。它会在发送端执行数据序列化(将会话转换为字符串),然后在接收端进行反序列化(即转换回数据结构)。

6

除非您完全控制客户端和服务器软件,否则您应该犹豫使用pickle来回传输数据。如果你确定你不知道的数据是可信的,那么Pickle是非常棒的,但如果它可能被篡改,它是不安全的。请参阅Why Python Pickle is Insecurepickle module documentation中的安全警告建议。

对于格式化数据来回发送来说,JSON是一个很好的选择; XML是好的,YAML非常好。简单的消息传递格式可能是发送消息数据的大小,分隔符(CRLF\r\n是常见的),然后是消息数据。

如果使用JSON,你就必须要么坚持使用json模块知道如何编码/解码,或写JSONEncoderJSONDecoder子类来处理你感兴趣的类型的对象。

下面是一个可以运行的概念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...' 
相关问题