hola,
estoy trabajando en envio y recepcion de datos a traves sockets "a pelo" (sin librerias añadidas). Los datos a transmitir pueden ser diccionarios, tablas de datos de Pandas, etc... El tamaño de cada envio `puede ser considerablemente grande o extremadamente pequeño.
No es lo mismo sock.recv(1024) que sock.recv(1024000).
El problema de dividr el objeto en pedazos lo tengo solventado de acuerdo con este articulo
y esta discusion en stackoverflow
en mi codigo lo he resumido asi:
Los datos de, digamos un diccionario, lo serializo con pickle (json tambien valdria) antes de enviarlo (sock.sendall)
¿como obtengo el tamaño en numero de bytes exacto de este objeto serializado?
He probado con sys.getsizeof(objeto), pero parece que no me funciona bien para el esquema mostrado arriba.
¿alguna sugerencia?
Edito:
me contesto a mi mismo. Parece que la solución es serializar a JSON. Esta pequeña librería funciona:
https://github.com/mdebbar/jsonsocket/bl...nsocket.py
La solución está en poder usar len(objeto) en lugar de sys.getsizeof(objeto) para obtener el numero de pytes. Las funciones clave son:
estoy trabajando en envio y recepcion de datos a traves sockets "a pelo" (sin librerias añadidas). Los datos a transmitir pueden ser diccionarios, tablas de datos de Pandas, etc... El tamaño de cada envio `puede ser considerablemente grande o extremadamente pequeño.
No es lo mismo sock.recv(1024) que sock.recv(1024000).
El problema de dividr el objeto en pedazos lo tengo solventado de acuerdo con este articulo
y esta discusion en stackoverflow
en mi codigo lo he resumido asi:
Código:
"""
definimos el método de conveniencia _send que prefija un mensaje dado con su
longitud antes de enviarlo a través de una conexión de socket determinada.
Será utilizado por el servidor para transmitir un mensaje de un cliente a
todos los demás clientes conectados.
"""
def _send(self, sock, msg):
"""
Prefija cada mensaje con una longitud de 4 bytes antes de enviar.
:param sock: el socket entrante
:param msg: el mensaje a enviar
"""
# Empaqueta el mensaje con 4 bytes en cabecera que representan la longitud del mensaje
msg = struct.pack('>I', len(msg)) + msg
# Envia el mensaje empaquetado
sock.send(msg)
"""
Definimos la función _receive que contiene la lógica de implementación de recepción de datos.
De acuerdo con el protocolo de mensajes que hemos elegido construir a través de TCP / IP,
cada mensaje del cliente tiene un prefijo de 4 bytes que representa su longitud.
Entonces, el servidor, a la recepcion de cada mensaje, lo descomprimirá y leerá sus
primeros 4 bytes para obtener la longitud.
Una vez que se ha adquirido esta información, el servidor llamará varias veces al
método recv para obtener el mensaje total.
"""
def _receive(self, sock):
"""
Recibe un mensaje entrante del cliente y lo desempaqueta.
:param sock: el socket entrante
:return: el mensaje desempaquetado
"""
data = None
# Recupera los primeros 4 bytes del mensaje
tot_len = 0
while tot_len < self.RECV_MSG_LEN:
msg_len = sock.recv(self.RECV_MSG_LEN)
tot_len += len(msg_len)
# Si el mensaje tiene los 4 bytes que representan la longitud ...
if msg_len:
data = ''
# Desempaqueta el mensaje y obtiene la longitud del mensaje
msg_len = struct.unpack('>I', msg_len)[0]
tot_data_len = 0
while tot_data_len < msg_len:
# Recupera el fragmento del tamaño máximo de RECV_BUFFER
chunk = sock.recv(self.RECV_BUFFER)
# Si no hay el pedazo esperado ...
if not chunk:
data = None
break # ... Simplemente sale del bucle
else:
# Une el contenido de los pedazos
data += chunk
tot_data_len += len(chunk)
return data
Los datos de, digamos un diccionario, lo serializo con pickle (json tambien valdria) antes de enviarlo (sock.sendall)
¿como obtengo el tamaño en numero de bytes exacto de este objeto serializado?
He probado con sys.getsizeof(objeto), pero parece que no me funciona bien para el esquema mostrado arriba.
¿alguna sugerencia?
Edito:
me contesto a mi mismo. Parece que la solución es serializar a JSON. Esta pequeña librería funciona:
https://github.com/mdebbar/jsonsocket/bl...nsocket.py
La solución está en poder usar len(objeto) en lugar de sys.getsizeof(objeto) para obtener el numero de pytes. Las funciones clave son:
Código:
def _send(socket, data):
try:
serialized = json.dumps(data)
except (TypeError, ValueError), e:
raise Exception('You can only send JSON-serializable data')
# send the length of the serialized data first
socket.send('%d\n' % len(serialized))
# send the serialized data
socket.sendall(serialized)
def _recv(socket):
# read the length of the data, letter by letter until we reach EOL
length_str = ''
char = socket.recv(1)
while char != '\n':
length_str += char
char = socket.recv(1)
total = int(length_str)
# use a memoryview to receive the data chunk by chunk efficiently
view = memoryview(bytearray(total))
next_offset = 0
while total - next_offset > 0:
recv_size = socket.recv_into(view[next_offset:], total - next_offset)
next_offset += recv_size
try:
deserialized = json.loads(view.tobytes())
except (TypeError, ValueError), e:
raise Exception('Data received was not in JSON format')
return deserialized