Skip to main content
 首页 » 编程设计

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

2025年05月04日16cmt

我正在研究一款 2 人游戏(类似于俄罗斯方 block )的网络部分,我正在尝试将游戏网格从客户端传递到服务器,反之亦然。但是,当我尝试使用 send(grid) 时,我得到一个 TypeError: send() argument 1 must be string or read-only buffer, not instance。

有没有办法规避这个问题,或者我是否必须将我的网格实例转换成一个字符串,然后从另一边解释它?提前致谢!

请您参考如下方法:

除非您完全控制客户端和服务器软件,否则您应该犹豫是否使用 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...'