Python3 JSON ошибка кодирования «строковый аргумент без кодировки» при переносе кода python 2.7x на python 3.7x - PullRequest
0 голосов
/ 16 января 2020

Я портирую python 2.7x код на python 3.7x. Этот код пытается отправить некоторые данные на сервер с помощью сокета TCP. Я получаю ошибку кодирования при создании JSON .dumps (data).

 try:
         sei_nal_unit = create_sei_nal_unit(camera_config.SEI_UUID_CAMERA_SETTINGS, 
                        json.dumps(capture_settings) )
         #connection_filehandle.write(sei_nal_unit)
     except Exception as e:
          log.write("socket Thread TCP - exception in sending data [%s]" % (str(e)) ) 

   def encode_multibyte_value(value):
        """ encode values >= 255 as 0xff0xff..0xresidual """

        encoded = bytearray()

        while (value >= 255):
            encoded += bytearray(chr(255))
            value -= 255

        encoded += bytearray(chr(value))

        return encoded

    def escape_bytearray(input):
        """ escape 000 to 0030, 001 to 0031, 002 to 0032 and 003 to 0033 """
        output = bytearray()

        history1 = None
        history2 = None

        for b in input:
            if (history1==0) and (history2==0) and (b <= 3):
                output += chr(3)
                history1 = 3
                history2 = b
            else:
                history1 = history2
                history2 = b

            output += chr(b)    

        return output


       def create_sei_nal_unit(uuid, payload_string):
        """ create a 'user data unregistered' SEI nal unit in a bytearray """
        try:
            assert(bytearray == type(uuid))
            uuid_length = len(uuid)
            assert(16 == uuid_length)
            nal_unit_prefix = bytearray(b'\x00\x00\x00\x01')
            nal_unit_type = bytearray(chr(6))                   # 6 = SEI
            encoded_payload_type = encode_multibyte_value(5)    # 5 = 'user data unregistered'
            payload = bytearray(payload_string)
            encoded_payload_size = encode_multibyte_value(uuid_length + len(payload))
            escaped_payload = escape_bytearray(uuid + payload)
            trailing_bits = bytearray(b'\x80')
            sei_nal_unit = ( nal_unit_prefix
                       + nal_unit_type
                       + encoded_payload_type
                       + encoded_payload_size
                       + escaped_payload
                       + trailing_bits )
            return sei_nal_unit
        except Exception as e:
            print(str(e))

и ошибка

socket Thread TCP - an exception in sending data [string argument without an encoding]

Файл JSON равен

capture_settings = [{"framerate": 30, "width": 1280, "height": 720, "bitrate": 17000000, "overlay": false, "gop_size": 30}]

Я не нашел никакой подсказки, я пытался много раз, но не надеялся. Спасибо, продвинутый.

Я пытался на вашем пути, но это не работает, может быть, я делаю что-то не так. выходные данные python2 и выходные данные python3 отличаются, и сервер не исключает данные. Пожалуйста, смотрите код python2 и его вывод, а также код python3 и его вывод

Python 2 код

    import json

capture_settings= [{"framerate": 30, "width": 1280, "height": 720, "bitrate": 17000000, "overlay": False, "gop_size": 30}]

SEI_UUID_CAMERA_SETTINGS = bytearray(b'\x08\x94\xfc\xa2\x58\xce\x45\x02\x8f\x18\xc0\x8c\x68\xe5\x32\x35')
#print(len(SEI_UUID_CAMERA_SETTINGS))
#""" encode values >= 255 as 0xff0xff..0xresidual """
def encode_multibyte_value(value):
    """ encode values >= 255 as 0xff0xff..0xresidual """

    encoded = bytearray()

    while (value >= 255):
        encoded += bytearray(chr(255))
        value -= 255

    encoded += bytearray(chr(value))

    return encoded

def escape_bytearray(input):
    """ escape 000 to 0030, 001 to 0031, 002 to 0032 and 003 to 0033 """
    output = bytearray()

    history1 = None
    history2 = None

    for b in input:
        if (history1==0) and (history2==0) and (b <= 3):
            output += chr(3)
            history1 = 3
            history2 = b
        else:
            history1 = history2
            history2 = b

        output += chr(b)    

    return output


def create_sei_nal_unit(uuid, payload_string):
    """ create a 'user data unregistered' SEI nal unit in a bytearray """

    assert(bytearray == type(uuid))
    print(uuid)

    uuid_length = len(uuid)
    assert(16 == uuid_length)   

    nal_unit_prefix = bytearray(b'\x00\x00\x00\x01')
    nal_unit_type = bytearray(chr(6))                   # 6 = SEI

    encoded_payload_type = encode_multibyte_value(5)    # 5 = 'user data unregistered'

    payload = bytearray(payload_string)

    encoded_payload_size = encode_multibyte_value(uuid_length + len(payload))
    print(uuid + payload)
    escaped_payload = escape_bytearray(uuid + payload)


    trailing_bits = bytearray(b'\x80')

    sei_nal_unit = ( nal_unit_prefix
                   + nal_unit_type
                   + encoded_payload_type
                   + encoded_payload_size
                   + escaped_payload
                   + trailing_bits )

    return sei_nal_unit

sei_nal_unit = create_sei_nal_unit(SEI_UUID_CAMERA_SETTINGS, json.dumps(capture_settings))
print(sei_nal_unit)

и его вывод

x���X�E���h�25 [{"overlay": false, "gop_size": 30, "частота кадров": 30, "высота": 720, "ширина": 1280, "битрейт" : 17000000}] �

Код python3

 import json


capture_settings= [{"framerate": 30, "width": 1280, "height": 720, "bitrate": 17000000, "overlay": False, "gop_size": 30}]

SEI_UUID_CAMERA_SETTINGS = b'\x08\x94\xfc\xa2\x58\xce\x45\x02\x8f\x18\xc0\x8c\x68\xe5\x32\x35'
#print(len(SEI_UUID_CAMERA_SETTINGS))
#""" encode values >= 255 as 0xff0xff..0xresidual """
def encode_multibyte_value(value):
    """ encode values >= 255 as 0xff0xff..0xresidual """

    encoded = bytes()

    while (value >= 255):
        encoded += bytes(chr(255).encode('utf-8'))
        value -= 255

    encoded += bytes(chr(value).encode('utf-8'))

    return encoded

def escape_bytearray(input):
    """ escape 000 to 0030, 001 to 0031, 002 to 0032 and 003 to 0033 """
    output = bytes()

    history1 = None
    history2 = None

    for b in input:
        if (history1==0) and (history2==0) and (b <= 3):
            output += b'\x03'
            history1 = 3
            history2 = b
        else:
            history1 = history2
            history2 = b

        output += chr(b).encode('utf-8')    

    return output


def create_sei_nal_unit(uuid, payload_string):
    """ create a 'user data unregistered' SEI nal unit in a bytearray """

    assert(bytes == type(uuid))

    uuid_length = len(uuid)
    assert(16 == uuid_length)   

    nal_unit_prefix = b'\x00\x00\x00\x01'
    nal_unit_type = b'\x06'                  # 6 = SEI
    encoded_payload_type = encode_multibyte_value(5)    # 5 = 'user data unregistered'

    payload = bytes(payload_string)

    encoded_payload_size = encode_multibyte_value(uuid_length + len(payload))
    escaped_payload = escape_bytearray(uuid + payload)


    trailing_bits = b'\x80'

    sei_nal_unit = ( nal_unit_prefix
                   + nal_unit_type
                   + encoded_payload_type
                   + encoded_payload_size
                   + escaped_payload
                   + trailing_bits )

    return sei_nal_unit

sei_nal_unit = create_sei_nal_unit(SEI_UUID_CAMERA_SETTINGS, json.dumps(capture_settings).encode('utf-8'))
print(sei_nal_unit)

Его вывод

b '\ x00 \ x00 \ x00 \ x01 \ x06 \ x05x \ x08 \ xc2 \ x94 \ xc3 \ xbc \ xc2 \ xa2X \ xc3 \ x8eE \ x02 \ xc2 \ x8f \ x18 \ xc3 \ x80 \ xc2 \ x8ch \ xc3 \ xa525 [{"частота кадров": 30, " ширина ": 1280," высота ": 720," битрейт ": 17000000," оверлей ": ложь," gop_size ": 30}] \ x80 '

на python2 сервере, исключая данные но в python3 это не исключая данные. пожалуйста, дайте мне в чем ошибка в python3 коде. Спасибо.

1 Ответ

1 голос
/ 16 января 2020

Вызов json.dumps() возвращает строку. Вы должны закодировать это в bytes перед отправкой через TCP-сокет. Самое простое - использовать:

json.dumps(capture_settings).encode('ascii')

По умолчанию json.dumps() гарантирует, что все не-ascii символы полностью экранированы в строке, поэтому вы можете безопасно использовать .encode('ascii') для преобразования строки в bytes.

(Существует параметр ensure_ascii, который можно установить False для ситуаций, когда вы знаете, что сервер может обрабатывать другие кодировки, такие как utf-8, но здесь достаточно просто использовать ascii.)

Также вы не можете сделать bytearray(chr(6)), так как bytearray() принимает параметр bytes и chr() возвращает строку. bytearray(b'\06') будет работать, но весь этот код, вероятно, будет проще, если работать непосредственно со значениями bytes вместо bytearray.

bytearray - это изменяемая последовательность байтов, если только вам не нужна изменчивость, попробуйте просто использовать bytes напрямую.

Если вы переименуете параметр в payload_bytes (потому что теперь вы передаете байты), то это, вероятно, работает (вы можете объединить bytes и bytearray):

        nal_unit_prefix = b'\x00\x00\x00\x01'
        nal_unit_type = b'\x06'                  # 6 = SEI
        encoded_payload_type = encode_multibyte_value(5)    # 5 = 'user data unregistered'

        encoded_payload_size = encode_multibyte_value(uuid_length + len(payload))
        escaped_payload = escape_bytearray(uuid + payload_bytes)
        trailing_bits = b'\x80'
        sei_nal_unit = ( nal_unit_prefix
                   + nal_unit_type
                   + encoded_payload_type
                   + encoded_payload_size
                   + escaped_payload
                   + trailing_bits )
...