отправка/получение файла UDP в python

Я сделал эти сценарии отправки/получения, но я повредил файл! я понятия не имею, почему я получаю эту проблему!

отправитель.py

#!/usr/bin/env python

from socket import *
import sys

s = socket(AF_INET,SOCK_DGRAM)
host =sys.argv[1]
port = 9999
buf =1024
addr = (host,port)

file_name=sys.argv[2]

f=open(file_name,"rb") 
data = f.read(buf)

s.sendto(file_name,addr)
s.sendto(data,addr)
while (data):
    if(s.sendto(data,addr)):
        print "sending ..."
        data = f.read(buf)
s.close()
f.close()

приемник.py

#!/usr/bin/env python

from socket import *
import sys
import select

host="0.0.0.0"
port = 9999
s = socket(AF_INET,SOCK_DGRAM)
s.bind((host,port))

addr = (host,port)
buf=1024

data,addr = s.recvfrom(buf)
print "Received File:",data.strip()
f = open(data.strip(),'wb')

data,addr = s.recvfrom(buf)
try:
    while(data):
        f.write(data)
        s.settimeout(2)
        data,addr = s.recvfrom(buf)
except timeout:
    f.close()
    s.close()
    print "File Downloaded"

и это оригинальный приемник, который я модифицировал (работает нормально 100%)

#!/usr/bin/env python

from socket import *
import sys
import select

host="0.0.0.0"
port = 9999
s = socket(AF_INET,SOCK_DGRAM)
s.bind((host,port))

addr = (host,port)
buf=1024

f = open("file.pdf",'wb')

data,addr = s.recvfrom(buf)
try:
    while(data):
        f.write(data)
        s.settimeout(2)
        data,addr = s.recvfrom(buf)
except timeout:
    f.close()
    s.close()
    print "File Donwloaded"

как вы заметили, он создает файл в начале.

требуемый: клиент => отправить файл (name.ext) => сервер: сохранить его (name.ext)

мой вывод: поврежденный файл для pdf и пустой для txt


person Hamoudaq    schedule 21.12.2012    source источник
comment
Прежде всего: except socket.timeout: никогда не сработает. Вы делаете from socket import *, поэтому socket в вашем коде на самом деле socket.socket. Вы должны делать except timeout или использовать import socket (настоятельно рекомендуется).   -  person Thomas Orozco    schedule 21.12.2012
comment
я получил socket.timeout: тайм-аут ,,,, и когда я отправляю pdf-файл, а затем открываю его, он говорит, что это поврежденный файл, у меня есть базовые знания о UDP. Я попробовал свой код, который я предоставил в вопросе, спасибо ты   -  person Hamoudaq    schedule 21.12.2012
comment
@ThomasOrozco спасибо, вы исправили часть ошибки, но у меня есть другая проблема, если я отправляю небольшой файл, он не остановится (менее 1028), но когда я отправляю большой файл, он работает нормально, я думаю о изменение размера буфера   -  person Hamoudaq    schedule 21.12.2012


Ответы (2)


Проблема с вашим кодом:

  • Когда данные отправляются через сокеты, обычно нижние уровни объединяют данные из нескольких вызовов sendTo и отправляют их вместе, чтобы снизить нагрузку на сеть.
  • Вы отправляете первые 1024 байта файла дважды.

Что ты должен делать:

Используйте какую-то строку-разделитель, содержащую пару символов (например, «**_$$»), чтобы она не существовала в фактическом двоичном представлении файла. Затем добавьте этот разделитель в конец имени файла.

Прочитайте из файла еще раз перед запуском цикла while.

На стороне получателя получите все в один поток, а затем разделите с помощью разделителя. У вас будет имя файла и данные файла.

Обновление:

Рабочий код (Ubuntu/Windows XP)

# ----- sender.py ------

#!/usr/bin/env python

from socket import *
import sys

s = socket(AF_INET,SOCK_DGRAM)
host =sys.argv[1]
port = 9999
buf =1024
addr = (host,port)

file_name=sys.argv[2]

s.sendto(file_name,addr)

f=open(file_name,"rb")
data = f.read(buf)
while (data):
    if(s.sendto(data,addr)):
        print "sending ..."
        data = f.read(buf)
s.close()
f.close()

# ----- receiver.py -----

#!/usr/bin/env python

from socket import *
import sys
import select

host="0.0.0.0"
port = 9999
s = socket(AF_INET,SOCK_DGRAM)
s.bind((host,port))

addr = (host,port)
buf=1024

data,addr = s.recvfrom(buf)
print "Received File:",data.strip()
f = open(data.strip(),'wb')

data,addr = s.recvfrom(buf)
try:
    while(data):
        f.write(data)
        s.settimeout(2)
        data,addr = s.recvfrom(buf)
except timeout:
    f.close()
    s.close()
    print "File Downloaded"

Использование

>> python recevier.py

>> python sender.py localhost filename.txt
person ATOzTOA    schedule 21.12.2012
comment
f.write(str[1]) IndexError: индекс списка вне допустимого диапазона - person Hamoudaq; 21.12.2012
comment
Ошибка означает, что в полученных данных нет разделителя. Попробуйте отправить текстовый файл и распечатать все полученные данные... - person ATOzTOA; 21.12.2012
comment
попробовал с pdf и получил TypeError: аргумент file() 1 должен быть закодированной строкой без NULL байтов, а не str пробовал с txt и получил IndexError: список индексов вне диапазона - person Hamoudaq; 21.12.2012
comment
windows, я думаю, что это не имеет ничего общего с ОС - person Hamoudaq; 22.12.2012
comment
получил ту же ошибку! Я считаю, что проблема в получателе, а не в отправителе - person Hamoudaq; 22.12.2012
comment
Он отлично работает в Ubuntu с Python 2.6. Пожалуйста, обновите свой вопрос, указав последний код, который вы пытаетесь использовать, и сообщение об ошибке, включая номера строк. - person ATOzTOA; 22.12.2012
comment
Но если файл слишком большой (я использую png размером 22 КБ), содержимое усекается случайным образом на стороне получателя (тестирование на удаленной машине). Думаю дело не в коде, а в использовании UDP. - person Parmaia; 19.11.2013
comment
@Parmaia Мы использовали это для больших файлов (1M+) и не сталкивались с проблемами. - person ATOzTOA; 20.11.2013

Здесь есть две проблемы:

Синтаксические ошибки:

Вы используете from socket import *. Это не ошибка сама по себе, но она становится ошибкой, когда вы выполняете except socket.timeout.

Используя UDP:

При использовании UDP повреждение не должно быть сюрпризом. Вы, вероятно, не хотите использовать здесь UDP, вам следует переключиться на TCP.

Вот почему UDP здесь не подходит:

  • Пакеты могут быть потеряны, но другие все равно могут достичь адресата.
  • Пакеты могут дублироваться
  • Пакеты могут приходить в неправильном порядке

Обратите внимание, что переход на TCP потребует некоторого рефакторинга вашего кода (это немного сложнее, чем простая замена SOCK_DGRAM на SOCK_STREAM), но в вашем случае вы должны это сделать.


Я не говорю, что UDP плохой, но в вашем случае он не подходит.

person Thomas Orozco    schedule 21.12.2012
comment
но у меня есть другой скрипт, который получает файл без повреждения, но проблема с этим скриптом заключается в том, что он просто получает файл и называет его случайным именем, я просто взял его и изменил, чтобы получить имя и файл от клиента - person Hamoudaq; 21.12.2012
comment
@EngHamoud Вам нужно будет предоставить дополнительную информацию (ожидаемый и фактический результат), если вам нужна помощь в этом! :) - person Thomas Orozco; 21.12.2012
comment
если бы мне пришлось угадывать, я бы сказал, что причина, по которой ему приходится создавать такую ​​программу для передачи файлов по UDP, заключается в том, что это какое-то школьное задание по созданию программы для передачи файлов по протоколу UDP... потому что единственный причина, по которой я могу использовать UDP для передачи файлов, заключается в том, чтобы объяснить, как работает TCP... потому что для создания надежной программы передачи файлов UDP вам нужно будет обработать потерянные пакеты и собрать файл из пакеты, отправленные не по порядку а-ля bittorrent... и вам также понадобится какой-то терминатор, отправленный в конце, чтобы получатель знал, что он завершен. - person Cari; 10.12.2013