transferencia de archivos de socket Python

Estoy tratando de escribir archivos de transferencia o trozos de datos a través de un socket. Siento que estoy reinventando la rueda, pero mis búsquedas de una solución simple han fallado (todo lo que encuentro es demasiado simple o demasiado complejo). El servidor se ejecutaría en un teléfono con Python 2.5.4. La aplicación prevista sería sincronizar archivos de música entre el teléfono y una computadora host.

Estas son las entrañas de lo que tengo, que parece funcionar. Envio y recibo “ok” para romper los flujos.

¿Es una técnica razonable enviar ‘ok’ de ida y vuelta esencialmente como bits de parada para dividir flujos de datos?

¿Hay una manera estándar de hacer esto?

La ejecución de cualquier tipo de servidor de biblioteca (ftp, http) en el teléfono no es una solución útil dados los límites de la memoria y la capacidad de procesamiento del teléfono.

servidor:

import socket c = socket.socket(socket.AF_INET,socket.SOCK_STREAM) c.bind(('', 1234)) c.listen(1) s,a = c.accept() while True: data = s.recv(1024) cmd = data[:data.find('\n')] if cmd == 'get': x, file_name, x = data.split('\n', 2) s.sendall('ok') with open(file_name, 'rb') as f: data = f.read() s.sendall('%16d' % len(data)) s.sendall(data) s.recv(2) if cmd == 'end': s.close() c.close() break 

cliente:

 import socket s = socket.socket() s.connect(('192.168.1.2', 1234)) def get_file(s, file_name): cmd = 'get\n%s\n' % (file_name) s.sendall(cmd) r = s.recv(2) size = int(s.recv(16)) recvd = '' while size > len(recvd): data = s.recv(1024) if not data: break recvd += data s.sendall('ok') return recvd print get_file(s, 'file1') print get_file(s, 'file2') s.sendall('end\n') 

¿Es una técnica razonable enviar ‘ok’ de ida y vuelta esencialmente como bits de parada para dividir flujos de datos?

La mayoría de los protocolos usan algún terminador u otro. Las alternativas populares son ‘\ r \ n’, ‘\ r \ n \ r \ n’ o EOF (ctrl + d), pero estas solo se eligen arbitrariamente y no son mejores ni peores que su ‘ok’, siempre que su cliente y el servidor sabe como manejarlo.

¿Hay una manera estándar de hacer esto?

Sí. http://www.faqs.org/rfcs/rfc959.html

Describe la forma estándar de hacer esto.

Aquí hay una implementación: http://docs.python.org/library/ftplib.html

Tu código se ve bien.

En realidad no es necesario enviar el tamaño del archivo. Se puede usar en while True , ya que la verificación if not data: break detendrá el ciclo.

 while True: data = s.recv(1024) if not data: print " Done "; break recvd += data 

Además, ¿por qué está enviando ‘ok’ si el otro lado no lo comprueba? Estás saltando 2 bytes en cada lado.

¿No necesitas atender a múltiples clientes? ¿No hay necesidad de multihilo?

U puede ver esta implementación. También se encarga de si el archivo está en un subdirectorio. Aquí está el enlace !

servidor

 import socket import os print('Waiting for clinet to connect...') c = socket.socket(socket.AF_INET, socket.SOCK_STREAM) c.bind(('', 1234)) c.listen(1) s, a = c.accept() print('Connected. Going to receive file.') s.sendall('getfilename') filename = s.recv(1024) if '/' in filename: dir = os.path.dirname(filename) try: os.stat(dir) except: print('Directory does not exist. Creating directory.') os.mkdir(dir) f = open(filename, 'wb') print('Filename: ' + filename) while True: s.sendall('getfile') size = int(s.recv(16)) print('Total size: ' + str(size)) recvd = '' while size > len(recvd): data = s.recv(1024) if not data: break recvd += data f.write(data) #print(len(recvd)) break s.sendall('end') print('File received.') s.close() c.close() f.close() 

cliente

 import socket import sys if len(sys.argv) > 1 : print('Trying to connect...') s = socket.socket() s.connect(('127.0.0.1', 1234)) print('Connected. Wating for command.') while True: cmd = s.recv(32) if cmd == 'getfilename': print('"getfilename" command received.') s.sendall(sys.argv[1]) if cmd == 'getfile': print('"getfile" command received. Going to send file.') with open(sys.argv[1], 'rb') as f: data = f.read() s.sendall('%16d' % len(data)) s.sendall(data) print('File transmission done.') if cmd == 'end': print('"end" command received. Teminate.') break 

rsync es la forma estándar de sincronizar archivos entre dos computadoras. Puedes escribirlo en Python como este http://code.activestate.com/recipes/577518-rsync-algorithm/ o puedes envolver la biblioteca de C como este http://freshmeat.net/projects/pysync/ con algunos ajustes Como reemplazar el MD4 con el MD5.

O, si desea hacer esto a nivel de socket, realmente debería usar asynchat con asyncore. Aquí hay un servidor FTP escrito con asynchat http://pyftpdlib.googlecode.com/svn-history/r20/trunk/pyftpdlib/FTPServer.py pero debes comenzar leyendo http://www.doughellmann.com/PyMOTW/asynchat / Preste atención a la parte sobre el punto 2 de Terminadores de mensajes. Muchos protocolos de red hacen cosas extrañas como esta, es decir, a veces envían y reciben comandos y respuestas de línea completa, y a veces envían y reciben fragmentos de datos arbitrarios precedidos por el conteo de cuantos bytes hay en el trozo Puede manejar esto mucho más fácilmente con asynchat, y su progtwig también se escalará mucho mejor.