O módulo struct é uma ferramenta nativa do Python que facilita a conversão entre tipos de dados Python e estruturas binárias. Em comunicações via socket, os dados são frequentemente transmitidos como fluxos binários. O struct permite empacotar tipos específicos em bytes de formato fixo para envio pela rede, e também oferece a funcionalidade reversa de desempacotamento para reconstruir os dados originais no destino.
Como o struct Funciona
O módulo transforma números de qualquer tamanho em uma sequência de bytes de comprimento fixo (escolhido pelo usuário). Isso lembra funções hash, onde a saída tem tamanho constante independentemente da entrada, mas difere porque hashes são irreversíveis e aceitam dados como texto, strings, etc. O struct, por outro lado, permite reverter o processo e obter os valores originais.
Atenção: O módulo trabalha apenas com números; não converte strings ou outros objetos diretamente.
Operações Básicas: pack e unpack
Exemplo de uso correto (a tabela de formatos está mais adiante):
import struct
# Empacotar um inteiro
data = struct.pack("i", 1234566)
print(data) # b'\x86\xd6\x12\x00'
print(type(data)) # <class 'bytes'>
# Desempacotar usando o mesmo formato
original = struct.unpack("i", data)
print(original) # (1234566,)
print(type(original)) # <class 'tuple'>
print(original[0]) # 1234566
Exemplo de erro ao passar tipo incorreto:
import struct
# Isso gera uma exceção: struct.error: required argument is not an integer
# res = struct.pack("i", "1231")
Erro ao usar formatos diferentes no empacotamento e desempacotamento:
import struct
res = struct.pack("i", 123)
# Isso causa erro: struct.error: unpack requires a buffer of 8 bytes
# res2 = struct.unpack("q", res)
Empacotando e desempacotanod múltiplos valores:
import struct
# Empacota três valores com formatos diferentes
packed = struct.pack("hiq", 12, 23, 451312)
print(packed) # b'\x0c\x00\x00\x00\x17\x00\x00\x00\xf0\xe2\x06\x00\x00\x00\x00\x00'
print(type(packed)) # <class 'bytes'>
# Desempacota e atribui a variáveis
a, b, c = struct.unpack("hiq", packed)
print(a, b, c) # 12 23 451312
Exemplo de erro ao desempacotar com número incorreto de valores:
# Supondo que escrevemos 5 números em um arquivo
with open("data.bin", "wb") as f:
for i in range(5):
f.write(struct.pack("i", i))
# Tentar ler e desempacotar com formato único causa erro
with open("data.bin", "rb") as f:
data = f.read()
# Isto falha: struct.error: unpack requires a buffer of 4 bytes
# a, b, c, d, e = struct.unpack("i", data)
Aplicação em Comunicação Socket: Cabeçalhos de Tamanho Fixo
Você pode empacotar o comprimento de um cabeçalho JSON para enviar como prefixo em transmissões socket.
import struct
import json
header_info = {
"header_name": "a.txt",
"total_size": 22,
"hash": "shawn"
}
header_json = json.dumps(header_info)
packed_len = struct.pack("i", len(header_json))
# No lado receptor, desempacota para obter o tamanho
length_received = struct.unpack("i", packed_len)
print(length_received) # (60,)
print(length_received[0]) # 60
Tabela de Formatos e Tamanhos de Bytes
| Caractere (Format) | Tipo C | Tipo Python | Tamanho Padrão (bytes) |
|---|---|---|---|
| x | byte de preenchimento | sem valor | |
| c | char | string de 1 caractere | 1 |
| b | signed char | inteiro | 1 |
| B | unsigned char | inteiro | 1 |
| ? | _Bool | bool | 1 |
| h | short | inteiro | 2 |
| H | unsigned short | inteiro | 2 |
| i | int | inteiro | 4 |
| I | unsigned int | inteiro | 4 |
| l | long | inteiro | 4 |
| L | unsigned long | inteiro | 4 |
| q | long long | inteiro | 8 |
| Q | unsigned long long | inteiro | 8 |
| f | float | float | 4 |
| d | double | float | 8 |
| s | char[] | string | |
| p | char[] | string | |
| P | void* | inteiro |