передача файлов через сокет Python - PullRequest
7 голосов
/ 27 июля 2011

Я пытаюсь записать файлы передачи или фрагменты данных через сокет. Мне кажется, что я заново изобретаю колесо, но мои поиски простого решения не увенчались успехом (все, что я нахожу, слишком просто или слишком сложно). Сервер будет работать на телефоне под управлением Python 2.5.4. Предполагаемое приложение будет синхронизировать музыкальные файлы между телефоном и хост-компьютером.

Это то, что у меня есть, похоже, работает. Я отправляю и получаю «ОК», чтобы разбить потоки.

Является ли отправка 'ok' туда и обратно по существу в качестве стоп-битов для разделения потоков данных разумной методикой?

Есть ли стандартный способ сделать это?

Запуск любого вида библиотечного сервера (ftp, http) на телефоне не является полезным решением, учитывая ограничения памяти и вычислительной мощности телефона.

Сервер:

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

клиент:

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')

Ответы [ 5 ]

4 голосов
/ 27 июля 2011

Является ли отправка 'ok' туда и обратно по существу в качестве стоп-битов для разделения потоков данных разумным методом?

В большинстве протоколов используется тот или иной терминатор.Популярными альтернативами являются '\ r \ n', '\ r \ n \ r \ n' или EOF (ctrl + d), но они просто выбраны произвольно и ничем не хуже или лучше, чем ваше 'ок', если ваш клиенти сервер знает, как с этим справиться.

1 голос
/ 02 мая 2015

U может посмотреть на эту реализацию. Это также заботится о том, находится ли файл в подкаталоге. Вот ссылка !

сервер

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()

клиент

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
1 голос
/ 24 декабря 2012

Ваш код выглядит хорошо.

На самом деле вам не нужно отправлять через размер файла. Вы можете использовать while True, так как проверка if not data: break остановит цикл.

while True:
    data = s.recv(1024)

    if not data: print " Done "; break

    recvd += data

Кроме того, почему вы отправляете «хорошо», другая сторона не проверяет это? Вы просто пропускаете 2 байта с каждой стороны.

Разве вам не нужно обслуживать нескольких клиентов? Нет необходимости многопоточности?

1 голос
/ 27 июля 2011

Есть ли стандартный способ сделать это?

Да.http://www.faqs.org/rfcs/rfc959.html

Описывает стандартный способ сделать это.

Вот реализация: http://docs.python.org/library/ftplib.html

0 голосов
/ 27 июля 2011

rsync - это стандартный способ синхронизации файлов между двумя компьютерами.Вы можете написать это на Python, например, http://code.activestate.com/recipes/577518-rsync-algorithm/, или обернуть библиотеку C, например, http://freshmeat.net/projects/pysync/, с некоторыми изменениями, например, заменить MD4 на MD5.сделать это на уровне сокета, вы действительно должны использовать asynchat с asyncore.Вот FTP-сервер, написанный с помощью asynchat http://pyftpdlib.googlecode.com/svn-history/r20/trunk/pyftpdlib/FTPServer.py, но вы должны начать с чтения http://www.doughellmann.com/PyMOTW/asynchat/ Обратите внимание на часть, касающуюся пункта 2 терминатора сообщений. Многие сетевые протоколы делают такие странные вещи, напримерони отправляют и получают полные строки команд и ответов, а иногда отправляют и получают куски произвольных данных, которым предшествует количество байтов в чанке.Вы можете справиться с этим намного легче с помощью asynchat, и ваша программа будет также масштабироваться намного лучше.

...