[PYTHON]Ejemplo: transferir archivos por internet

Iniciado por WaAYa HaCK, 21 Febrero 2012, 15:15 PM

0 Miembros y 1 Visitante están viendo este tema.

WaAYa HaCK

Hola! Posteo un simple script de ejemplo para mostrar el funcionamiento de los sockets y demás en Python.

El script consta de un cliente y un servidor. Está escrito en catalán, pero es perfectamente inteligible.

Cliente:
Código (python) [Seleccionar]
# enviar.py v1.2
# -*- coding: cp1252 -*-
# ---------------
# Changelog:
# + Diccionaris
# + Avisos de lectura i transferencia
# + Funcions de mida d'arxiu

# importamos los modulos necesarios:
import socket, os
# definimos el puerto de control CPORT y el puerto multimedia MPORT
CPORT = 9091
MPORT = 9090
# una funcion para transformar un tamaño en bytes a un tamaño más fácil de leer:
def midafap(mida):
sufixos = [("B",2**10), ("K",2**20), ("M",2**30), ("G",2**40), ("T",2**50)]
for suf, lim in sufixos:
if mida > lim:
continue
else:
return round(mida/float(lim/2**10),2).__str__()+suf

print "Enviar arxius per INTRnet!"
# un diccionario, esto es por comodidad mía
# pedimos dónde estamos: el instituto, casa, o solo, para probar cosas
sel = raw_input("Indica el host remot(institut, casa, sol): ")
insdic = {"FAPFAPFAP" : '192.168.171.12',
           "FAPFAP" : '192.168.171.17',
           "FAP" : '192.168.171.19'}
casadic = {"SERVER" : '192.168.1.34'}
soldic = {"Me" : 'localhost'}
# ahora tenemos un diccionario dentro de otro:
bigdic = {"institut" : insdic,
           "casa" : casadic,
           "sol" : soldic}
final = bigdic[sel]
print final
# si hemos elegido "institut", nos dirá las IPs y escribimos FAPFAPFAP.
sel2 = raw_input("Indica el host remot de la llista: ")
HOST = final[sel2]

# el archivo en sí
FILE = raw_input("Arrossega l'arxiu: ")
# cambiamos comillas, para evitar errores en los archivos con espacios:
FILE = FILE.replace('"', '')
# creamos un socket que envía la ruta del archivo:
cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# se conecta al puerto de control:
cs.connect((HOST, CPORT))
# envía la ruta del archivo:
cs.send("SEND " + FILE)
cs.close()

# otro socket, que envía el archivo:
ms = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# se conecta al puerto multimedia:
ms.connect((HOST, MPORT))

# abrimos el archivo para leerlo:
f = open(FILE, "rb")
data = f.read()
f.close()

# obtenemos el tamaño del archivo, en bytes:
midabytes = os.path.getsize(FILE)
# usamos la función anterior para convertir el tamaño:
# Archivo guarra.fap leído (682,13M)
print "Arxiu ", FILE, "llegit (", str(midafap(midabytes)), ")."
# enviamos los datos del archivo:
ms.send(data)
ms.close()
# fin
print "Arxiu ", FILE, "enviat (", str(midafap(midabytes)), ")."
raw_input("Prem una tecla per tancar...")


Servidor:
Código (python) [Seleccionar]
# rebre.py

# importamos módulos, unos cuantos más...
import os, socket, time, string, sys, urlparse
from threading import *

#------------------------------------------------------------------------

# creamos un objeto de tipo StreamHandler:
class StreamHandler ( Thread ):
#creamos un inicializador:
    def __init__( this ):
        Thread.__init__( this ) # nos referimos al objeto mismo

    def run(this):
        this.process() #aquí tenemos un método que nos muestra que estamos trabajando con objetos de tipo socket.

    def bindmsock( this ):
        this.msock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # enlazamos el "this" al puerto 9090 (Multimedia):
        this.msock.bind(('', 9090))
        this.msock.listen(1)
        print '[INTR] Esperant al port 9090'

    def acceptmsock( this ):
        # aceptamos la conexión...
        this.mconn, this.maddr = this.msock.accept()
        print '[INTR] Ieepa, es connecta', this.maddr
   
    def bindcsock( this ):
        # enlazamos al puerto 9091 (Control):
        this.csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        this.csock.bind(('', 9091))
        this.csock.listen(1)
        print '[Control] Esperant al port 9091'

    def acceptcsock( this ):
        # aceptamos...
        this.cconn, this.maddr = this.csock.accept()
        print '[Control] Ieepa, es connecta', this.maddr
       
        while 1:
            # captamos datos:
            data = this.cconn.recv(1024)
            if not data: break
            # si los datos recibidos empiezan por SEND, captamos el nombre de archivo
            if data[0:4] == "SEND": this.filename = data[5:]
            print '[Control] Preparat per rebre "%s"' % this.filename
            break

    def transfer( this ):
        print '[INTR] Transferint dades de "%s"' % this.filename
        # captamos solamente el nombre de archivo y su extensión:
        nomfinal = os.path.basename(this.filename)
        # lo guardamos en el directorio de Recibido
        f = open("C:/INTRnet/Rebut/"+nomfinal,"wb")
        # ahora, el bucle que captura datos en sí:
        while 1:
            data = this.mconn.recv(1024)
            if not data: break
            f.write(data)
        f.close()

        # hemos escrito los datos en el nuevo archivo
        print '[Media] Rebut "%s"' % this.filename
        print '[Media] Tancant el flux de "%s"' % this.filename
        os.popen("msg.exe * S'ha rebut l'arxiu "+ nomfinal)
        # y ya hemos recibido el archivo!
   
    def close( this ):
        # cerramos todos los sockets:
        this.cconn.close()
        this.csock.close()
        this.mconn.close()
        this.msock.close()

    def process( this ):
        # siempre aceptamos las conexion
        while 1:
            this.bindcsock()
            this.acceptcsock()
            this.bindmsock()
            this.acceptmsock()
            this.transfer()
            this.close()

#------------------------------------------------------------------------

# creamos un objeto StreamHandler:
s = StreamHandler()
# usamos el método de Thread (dentro del módulo threading) para iniciar:
s.start()
#fin


Eso es todo. Funciona de maravilla en redes locales, y por IP pública o No-IP también ;)

El problema viene en los archivos con acentos, que dan error. Haré un filtro para eliminar los carácteres.

Cualquier duda, comentad!
La cacatúa yoyó es nueva en el zoo!

Jirp96

Hola!
Esta muy bueno, lo voy a guardar para leerlo(y entenderlo xD)
Por cierto, tengo una duda sobre la clase StreamHandler: por que usas "this" en ves de self? es por alguna razon en particular o yo estoy confundido y "this" no lo usas para lo mismo que se usaría self? :huh:
Saludos!

WaAYa HaCK

Es cosa del threading, lo probé con self, claro, y no funcionaba. Busqué por internet y me salió que debía usar this. Pues hala.

Saludos!
La cacatúa yoyó es nueva en el zoo!

Eleкtro

Me mataste!
Tu script es más complicado de lo que imaginaba, Ya por el principio me pierdo con CPORT y MPORT no se para que sirven esos puertos... Tengo que estudiar cada cosa del script poco a poco xD , Lo único que entiendo de ahí es el catalá y poco más :xD

Está molt currat :) y muy explicado, se agradece, Aunque si haces uno para enviar archivos a mediafire, Mejor  >:D

Un saludo

PD:
Citar{"FAPFAPFAP" : '192.168.171.12',
"FAPFAP" : '192.168.171.17',
"FAP" : '192.168.171.19'}

XD








WaAYa HaCK

CPORT y MPORT son dos puertos diferentes. En el puerto de control, envío una cadena con la ruta del archivo, para que pueda guardarse. En el puerto de multimedia, envío los datos del archivo.

En FAPFAPFAP estaban los nombres de mis amigos ;) usamos el script para pasarnos "apuntes". El problema es que la Wifi del insti está capada, y a veces no funciona. Entonces, Skype o Dropbox. Pero, cuando me paso cosas con mi padre, funca de fruta madre  ;D
La cacatúa yoyó es nueva en el zoo!

MacGyver87

'El hombre es mortal por sus temores e inmortal por sus deseos'