Отправка данных как экземпляров с использованием Python Sockets - PullRequest
1 голос
/ 01 мая 2010

Я работаю над сетевой частью игры для 2 игроков (по аналогии с тетрисом) и пытаюсь передать игровую сетку от клиента к серверу и наоборот. Однако, когда я попытался использовать send (grid), я получил TypeError: аргумент send () 1 должен быть строковым или доступным только для чтения буфером, а не экземпляром.

Есть ли способ обойти это, или мне нужно преобразовать свой экземпляр сетки в строку, а затем интерпретировать его с другой стороны? Заранее спасибо!

Ответы [ 2 ]

6 голосов
/ 02 мая 2010

Если вы не имеете полного контроля над клиентским и серверным программным обеспечением, вам следует без колебаний использовать pickle для передачи данных назад и вперед. Pickle - это здорово, если вы уверены, что данные, которые вы извлекаете, заслуживают доверия, но если они могли быть подделаны, они небезопасны. См. Почему Python Pickle небезопасен , или рекомендации по безопасности в документации модуля рассола .

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...'
1 голос
/ 01 мая 2010

Просмотр сериализации данных: рассол . Он будет выполнять сериализацию данных (читать разговоры в строку) на стороне отправителя, а затем десериализацию (то есть преобразовывать обратно в структуру данных) на стороне получателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...