Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Intentado comprender este codigo: Enviar archivo via socket
#1
Que tal amigos. LLevo ya un año aprendiendo python y actualmente estoy full trabajando en un programa tipo cliente - servidor via socket en python 3.10.

Expecificamente estoy buscando aprender a poder enviar cualquier tipo de archivo via socket. En este mismo foro un colega publico al parecer un excelente contenido pero debido a que carezco un poco de conocimiento no logro comprender todas las partes del codigo.

Adjunto link de la publicacion del colega y aqui mismo formulare lo que no entiendo que hace el codigo y ver si pueden hecharme una mano con ello. Creo que sera la forma mas eficiente para no hacerles perder tanto tiempo. De ante mano muchas gracias.

Link del colega : Enviar archivo vía socket en Python 3 - Recursos Python

preguntas:

1. stream : bytes() ¿que esta haciendo especificamente?
2. chunk = sck.recv(expected_bytes - received_bytes)  ¿Porque esta restanto una variable con otra?
3.stream += chunk   ¿ Que intenta sumar?
4.received_bytes += len(chunk) ¿creo que hace algo parecido al punto 3. creo que es un tipo append?, pero no estoy seguro.
5. filesize = struct.unpack(fmt, stream)[0] ¿realmente no logro comprender por completo qe intenta hacer aqui, es decir, se que intenta decodificar con unpack pero no comprendo poque mezcla las dos varibales y el [0]


6. 

Código:
def receive_file(sck: socket.socket, filename):
    # Leer primero del socket la cantidad de
    # bytes que se recibirán del archivo.
    filesize = receive_file_size(sck)
    # Abrir un nuevo archivo en donde guardar
    # los datos recibidos.
    with open(filename, "wb") as f:
        received_bytes = 0     ¿PORQUE NUEVAMENTE ESTABLECE QUE ESTA VARIABLE VALE 0?

Quien sera tan buena gente para ayudarme con el codigo. al menos solo con el del servidor porque el del cliente lo comprendo al menos mejor.....
Responder
#2
Hola, Brandon, bienvenido.

Te voy respondiendo por partes.

(08-08-2022, 12:10 AM)brandon santi escribió: 1. stream = bytes() ¿que esta haciendo especificamente?

Crea una nueva variable del tipo bytes. Este tipo de dato es como una lista de números entre 0 y 255 (que es lo que propiamente se entiende por "byte"). Se usa el tipo bytes porque la información en un socket se envía y recibe en ese formato.

(08-08-2022, 12:10 AM)brandon santi escribió: 2. chunk = sck.recv(expected_bytes - received_bytes)  ¿Porque esta restanto una variable con otra?

Tené en cuenta que esta línea pertenece a la función receive_file_size(), que se ocupa, como indica el nombre, de recibir el tamaño del archivo que se está por transmitir. Eso es lo primero que hace el código: informarle al otro extremo de la conexión cuántos bytes pesa el archivo que se está por enviar. Ahora bien, una vez que tenemos el tamaño del archivo, hay que primero convertirlo a una secuencia de bytes para poder enviarlo a través del socket. Eso es precisamente lo que se hace en las primeras líneas de send_file() del cliente:

Código:
# Obtener el tamaño del archivo a enviar.
filesize = os.path.getsize(filename)
# Informar primero al servidor la cantidad
# de bytes que serán enviados.
sck.sendall(struct.pack("<Q", filesize))

struct.pack("<Q", filesize) convierte el tamaño del archivo a una secuencia de bytes. Para poder recibir esa secuencia en el servidor, hay que saber cuál es su longitud (i. e. cuántos números entre 0 y 255 hay), que es lo que se obtiene con esta línea:

Código:
fmt = "<Q"
expected_bytes = struct.calcsize(fmt)

expected_bytes contiene el número de bytes que se esperan recibir para determinar el tamaño del archivo. Posiblemente esa secuencia de bytes se reciba con una sola llamada a sck.recv(). Pero no se puede estar seguro de esto: nunca sabés cuántos bytes va a devolver el recv(), así que hay que hacer un bucle y registrar, luego de cada llamada a esa función, cuántos bytes devolvió. Eso se va registrando en la variable received_bytes. Cuando received_bytes == expected_bytes, estamos seguros de que recibimos toda la información que esperábamos. Así que básicamente esta línea

Código:
chunk = sck.recv(expected_bytes - received_bytes) 

lo que hace es leer la información restante (lo que esperamos menos lo que ya recibimos, expected_bytes - received_bytes) del socket.

(08-08-2022, 12:10 AM)brandon santi escribió: 3.stream += chunk   ¿ Que intenta sumar?

La información del socket se recibe en "pedazos" (chunks), sobre todo en estos casos donde estamos leyendo archivos. En esa línea se agrega (+=) el pedazo de datos que se acaba de recibir a los datos que ya se recibieron (stream). Al finalizar el bucle, stream debe ser una secuencia de todos los pedazos recibidos.

(08-08-2022, 12:10 AM)brandon santi escribió: 4.received_bytes += len(chunk) ¿creo que hace algo parecido al punto 3. creo que es un tipo append?, pero no estoy seguro.

Esto es lo que te comentaba antes: se registra en la variable received_bytes la cantidad (o longitud, length) del pedazo (chunk) de información que se acaba de recibir. El chunk puede tener un tamaño variable, así que hay que calcularlo en tiempo de ejecución con len().

(08-08-2022, 12:10 AM)brandon santi escribió: 5. filesize = struct.unpack(fmt, stream)[0] ¿realmente no logro comprender por completo qe intenta hacer aqui, es decir, se que intenta decodificar con unpack pero no comprendo poque mezcla las dos varibales y el [0]

Acá se convierte la secuencia de bytes de nuevo a un número entero (o sea, el paso inverso al de las primeras líneas de la función send_file() del cliente). Por ejemplo, si el archivo pesa 100.000 bytes, el cliente envió la secuencia de bytes correspondiente a ese número, que es algo como \xa0\x86\x01\x00\x00\x00\x00\x00. Usando struct.unpack(), convertimos esa secuencia de bytes de nuevo al número entero original 100.000.

(08-08-2022, 12:10 AM)brandon santi escribió: 6. 

Código:
def receive_file(sck: socket.socket, filename):
    # Leer primero del socket la cantidad de
    # bytes que se recibirán del archivo.
    filesize = receive_file_size(sck)
    # Abrir un nuevo archivo en donde guardar
    # los datos recibidos.
    with open(filename, "wb") as f:
        received_bytes = 0     ¿PORQUE NUEVAMENTE ESTABLECE QUE ESTA VARIABLE VALE 0?

Acá ya estamos en la función receive_file(), así que esta variable received_bytes no debe confundirse con la variable received_bytes de la función receive_file_size(). Sin embargo, ambas variables, cada una en su contexto, cumplen el mismo rol: llevar un registro de la cantidad de bytes que se van recibiendo del socket.

Espero haberte esclarecido un poco las ideas. Es un tema intrincado. Teniendo ya varios años de docencia en Python y en programación en general, te recomiendo que no desesperes si no aprehendés el 100% del código. Está muy bueno que te intereses por saber cómo funciona todo y no te contentes con un simple copiar y pegar, pero también está bien permitirse no comprender ciertas cosas: recién llevás un año. Son conceptos que se van adquiriendo a lo largo de los años con la misma práctica.

Saludos
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)