unpack_from nécessite une zone tampon d'au moins 4 octets
Je suis de la réception d'un paquet de client, composé de plusieurs champs. J'ai lu tous les champs correctement, mais quand il s'agit de la dernière champ qui est tag_end, python me donne une erreur:
unpack_from nécessite une zone tampon d'au moins 4 octets non trouvé.
c'est le code:
def set_bin(self, buf):
"""Reads a vector of bytes (probably received from network or
read from file) and tries to construct the packet structure
from it, by reading each packet member from the buffer. This
is somehow like deserializing the packet.
"""
assert isinstance(buf, bytearray), 'buffer type is not valid'
offset = 0
print("$$$$$$$$$$$$$$$$ set bin $$$$$$$$$$$$$$$$$")
try:
(self._tag_start, self._version, self._checksum, self._connection_id,
self._packet_seq) = Packet.PACKER_1.unpack_from(str(buf), offset)
except struct.error as e:
print(e)
raise DeserializeError(e)
except ValueError as e:
print(e)
raise DeserializeError(e)
#I=4 H=2 B=1
offset = Packet.OFFSET_GUID #14 correct
self._guid = buf[offset:offset+Packet.UUID_SIZE] #14-16 correct
offset = Packet.OFFSET_GUID + Packet.UUID_SIZE
print("$$$$$$$$$$$$$$$$ GUID read successfully $$$$$$$$$$$$$$$$$")
try:
(self._timestamp_sec, self._timestamp_microsec, self._command,
self._command_seq, self._subcommand, self._data_seq,
self._data_length) = Packet.PACKER_3.unpack_from(str(buf), offset)
except struct.error as e:
print(e)
raise DeserializeError(e)
except ValueError as e:
print(e)
raise DeserializeError(e)
print("$$$$$$$$$$$$$$$$ timestamps read successfully $$$$$$$$$$$$$$$$$")
offset = Packet.OFFSET_AUTHENTICATE
self._username = buf[offset:offset + self.USERNAME_SIZE] #Saman
offset += self.USERNAME_SIZE
print("$$$$$$$$$$$$$$$$ username read successfully $$$$$$$$$$$$$$$$$")
self._password = buf[offset:offset+self.USERNAME_SIZE]
offset += self.PASSWORD_SIZE
print("$$$$$$$$$$$$$$$$ password read successfully $$$$$$$$$$$$$$$$$")
self._data = buf[offset:offset+self._data_length]
offset = offset + self._data_length
print("$$$$$$$$$$$$$$$$ data read successfully $$$$$$$$$$$$$$$$$")
try:
(self._tag_end,) = Packet.PACKER_4.unpack_from(str(buf), offset)
except struct.error as e:
print(e)
raise DeserializeError(e)
except ValueError as e:
print(e)
raise DeserializeError(e)
print("$$$$$$$$$$$$$$$$ tag end read successfully $$$$$$$$$$$$$$$$$")
if len(buf) != Packet.PACKER.size + self._data_length:
print('failed to deserialize binary data correctly and construct the packet due to extra data')
else:
print('@@@@@@@@@@@@@@@ Deserialized Successfully')
et c'est une des constantes utilisées dans le code:
STRUCT_FORMAT_STR = r'=IHIHH 16B IIHHHHH I 6c 9c' #Saman
STRUCT_FORMAT_STR_1 = r'=IHIHH'
STRUCT_FORMAT_STR_2 = r'=16B'
STRUCT_FORMAT_STR_3 = r'=IIHHHHH'
STRUCT_FORMAT_STR_4 = r'=I'
STRUCT_FORMAT_STR_5 = r'=6c'
STRUCT_FORMAT_STR_6 = r'=9c'
UUID_SIZE = 16
OFFSET_GUID = 14
#OFFSET_DATA = 48 #shifting offset data by 15 char
OFFSET_AUTHENTICATE = 48
PACKER = struct.Struct(str(STRUCT_FORMAT_STR)) #Saman
PACKER_1 = struct.Struct(str(STRUCT_FORMAT_STR_1))
PACKER_2 = struct.Struct(str(STRUCT_FORMAT_STR_2))
PACKER_3 = struct.Struct(str(STRUCT_FORMAT_STR_3))
PACKER_4 = struct.Struct(str(STRUCT_FORMAT_STR_4))
PACKER_5 = struct.Struct(str(STRUCT_FORMAT_STR_5))
PACKER_6 = struct.Struct(str(STRUCT_FORMAT_STR_6))
BYTES_TAG_START = PACKER_4.pack(TAG_START)
BYTES_TAG_END = PACKER_4.pack(TAG_END)
et l'initialisation du paquet d'objet, où il initialise les champs:
def init(self, **kwargs):
si 'buf' dans kwargs:
auto.set_bin(kwargs['buf'])
autre chose:
affirmer kwargs['commande'] dans le Paquet.RTCINET_COMMANDS.les valeurs de() et kwargs['commande'] dans le Paquet.RTCINET_COMMANDS.les valeurs de(), 'Undefined protocole de commande"
affirmer isinstance(kwargs['data'], bytearray), 'type non valide pour le champ de données'
pour le domaine de l'in ('commande', 'commande', 'données'):
setattr(self, '_' + champ, kwargs[champ])
self._tag_start = Packet.TAG_START
self._version = Packet.VERSION_CURRENT % (Packet.USHRT_MAX + 1)
self._checksum = Packet.CRC_INIT
self._connection_id = kwargs.get('connection_id', 0) % (Packet.USHRT_MAX + 1)
self._packet_seq = Packet.PACKET_SEQ
Packet.PACKET_SEQ = (Packet.PACKET_SEQ + 1) % (Packet.USHRT_MAX + 1)
self._guid = uuid.uuid4().bytes
dt = datetime.datetime.now()
self._timestamp_sec = int(time.mktime(dt.timetuple()))
self._timestamp_microsec = dt.microsecond
# self._command = kwargs['command']
self._command_seq = kwargs.get('command_seq', 0)
# self._subcommand = kwargs['subcommand']
self._data_seq = kwargs.get('data_seq', 0)
self._data_length = len(kwargs['data'])
self._username = Packet.USERNAME #Saman
self._password = Packet.PASSWORD
J'ai fait en sorte que j'ai lu tous les champs dans le bon ordre, comme il a été écrit dans le paquet par le programme client. mais encore, je ne parvenais pas à résoudre ce problème.
Avez-vous une idée de comment cela pourrait être résolu?
- Eh bien... quelle est la durée d'
buf
, et ne fait que la longueur de correspondre à ce que vous attendez? - Pourquoi faites-vous appel à
str(buf)
tous les coins? Lestruct
veut unbytes
oubytearray
ou d'autres tampon compatible, et vous avez unbytearray
. L'appel destr
sur qui transforme tout votre tampon dans une chaîne de caractères comme"bytearray(b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00@')"
, ce qui n'est évidemment pas de la même longueur que le réel tampon en général. - Je pense que le
assert()
au début c'est pas une bonne idée. Il existe plusieurs autres types de mise en œuvre de la mémoire tampon de l'API d'ailleursbytearray
, donc cela peut rejeter parfaitement les valeurs valides. Si la valeur donnée ne permet pas de mettre en œuvre la mémoire tampon de l'API de la premièreunpack()
va soulever l'exception appropriée de toute façon.
Vous devez vous connecter pour publier un commentaire.
Le problème semble être que vous êtes à la conversion de choses à
str
tous sur la place pour aucune bonne raison.Dans certains endroits, comme
PACKER_1 = struct.Struct(str(STRUCT_FORMAT_STR_1))
, elle rend le code moins lisible et compréhensible, mais n'affecte pas la sortie réelle. Par exemple,STRUCT_FORMAT_STR_1
est déjà unstr
, doncstr(STRUCT_FORMAT_STR_1)
est la mêmestr
.Mais dans d'autres endroits, c'est bien pire que ça. En particulier, regardez toutes les lignes comme
Packet.PACKER_1.unpack_from(str(buf), offset)
. Là,buf
est unbytearray
. (Il doit être, parce que vousassert
il.) L'appel destr
sur unbytearray
vous donne la représentation de chaîne de caractères quibytearray
. Par exemple:Que la représentation de chaîne est évidemment pas généralement allons avoir la même longueur que le tampon que vous représentez. Donc, il n'est pas étonnant que vous obtenez des erreurs sur la longueur de mal. (Et si vous avez vraiment pas de chance et n'ont pas de telles erreurs, vous seriez de lecture des ordures valeurs à la place.)
Alors, que devez-vous faire pour convertir la
bytearray
en quelque chose de lastruct
module peut gérer? Rien! Comme les docs dire:str()
sur les valeurs que vous ne voulez pas avoir la représentation de chaîne de. Qui est l'ensemble des valeurs que vous souhaitez utiliserunpack()
ouunpack_from()
avec.str
àstruct.unpack_from
soulève unTypeError
. Donc, soit ce n'est pas votre code, ou vous êtes en cours d'exécution Python 2.x et pas 3.x, ou si vous avez réaffectés le nomstr
à quelque chose d'autre que lastr
type quelque part, ou d'autre chose d'étrange se passe.python-3.x
?str()
appels. La premièreunpack()
appel que le code est déjà faux, car il fonctionne sur une représentation sous forme de chaîne d'unbytearray
. Il suffit de regarder l'exemple dans la réponse ci-dessus.