使用Python套接字将数据作为实例发送

Mel*_*Mel 1 python sockets

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

无论如何要绕过这个,或者我是否必须将我的网格实例转换为字符串然后从另一边解释它?提前致谢!

Mat*_*son 6

除非您完全控制客户端和服务器软件,否则您应该使用pickle来回传输数据.如果你确定你要打开的数据值得信赖,那么Pickle很棒,但是如果它被篡改了,它是不安全的.请参阅为什么Python Pickle是不安全的,或者pickle模块文档中的安全警示建议.

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...'
Run Code Online (Sandbox Code Playgroud)