Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Интернет и сети
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 22.01.2011, 01:03
evgeny_sh evgeny_sh вне форума
Прохожий
 
Регистрация: 22.01.2011
Сообщения: 4
Репутация: 10
По умолчанию Indy 9. Передача файла частями

Я к вам, господа, и вот по какому вопросу:
Возникла необходимость написания софтинки для передачи файлов в локальной сети.
Помучав гугль и полистав соответствующую литературу, остановился на Indy 9 IdTcpServer и IdTcpClient. Сервер включен и слушает порт, клиент время от времени передает определенные файлы. Методом проб и ошибок сварганил более - менее рабочий вариант. В процессе тестирования обнаружился один неприятный подвох - большие файлы, размером в несколько сотен Мб передаваться категорически отказываются, на стороне сервера создается файл 0 байт.
Короче говоря - пришел к выводу, что файл лучше передавать кусками, попробовал все это дело реализовать - ан нет, моих скромных познаний в этой области оказалось недостаточно. Перепробовал несколько вариантов - не то. Файл создается, что - то в него записывается, но размер в итоге отличается от оригинала.

Как я это вижу:
Клиент - файл загружается в FileStream, размер файла делится на размер блока(допустим 1000 байт) = получаем количество блоков. Отправляем на сервер количество блоков или размер файла. В цикле отправляем блоки, увеличивая с каждым проходом FileStream.Position на соответствующее значение.

Сервер - создаем FileStream, опять же в цикле записываем полученые от клиента блоки в какой - то промежуточный буфер, копируем в FIleStream (например FS.CopyFrom(...)). По получению последнего блока или достижению FS определенного размера выходим из цикла.

В общем буду весьма и весьма признателен за помощь в реализации всего этого безобразия. Ниже приведен код, который работает на данный момент и нуждается в доработке.

З.Ы. Я не студент, в армию не отправляйте.

Код:
...
    Server: TIdTCPServer;
    Client: TIdTCPClient;
...

procedure TForm1.Button1Click(Sender: TObject);
var
  FileName : String;
  FileSize   : Cardinal;
  p          : Pointer;
begin
  Client.Connect();
  FileName := 'C:\1.rar';
  with TFileStream.Create(FileName, fmOpenRead) do
  try
    FileName := ExtractFileName(FileName) + #00;
    GetMem(p, 256);
    try
      CopyMemory(p, @FileName[1], Length(FileName));
      Client.Socket.Send(p^, 256);
    finally
      FreeMem(p);
    end;
    FileSize := Size;
    Client.Socket.Send(FileSize, SizeOf(FileSize));
    GetMem(p, Size);
    try
      ReadBuffer(p^, Size);
      Client.Socket.Send(p^, Size);
    finally
      FreeMem(p);
    end;
  finally
  Free;
  end;
  Client.Disconnect;
end;

procedure TForm1.ServerExecute(AThread: TIdPeerThread);
var
  FileName : PChar;
  FileSize : Cardinal;
  FS : TFileStream;
begin
  GetMem(FileName, 256);
  try
    Athread.Connection.ReadBuffer(FileName^, 256);
    Athread.Connection.ReadBuffer(FileSize, SizeOf(FileSize));
    FS := TFileStream.Create(FileName, fmCreate);
    try
      aThread.Connection.ReadStream(FS, FileSize);
    finally
      FS.Free;
    end;
  finally
    FreeMem(FileName);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Server.Active := true;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Server.Active := false;
end;
Ответить с цитированием
  #2  
Старый 22.01.2011, 06:34
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,095
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

1. Файл, особенно бинарник. лучше всего запаковать в Base64.
2. Дело в том, что очередность прихода пакетов тебе не гарантированна. Поэтому придется кусочки складывать как есть (нумеруя их) и по приходу последнего собирать файл целиком.
3. А зачем ты работаешь на таком низком уровне? Возьми TIdFTPClient/TIdFTPServer. Повесь с паролем на нестандартный порт. При желании еще SSL можно прикрутить. Гораздо будет проще.
Ответить с цитированием
  #3  
Старый 22.01.2011, 11:55
evgeny_sh evgeny_sh вне форума
Прохожий
 
Регистрация: 22.01.2011
Сообщения: 4
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
1. Файл, особенно бинарник. лучше всего запаковать в Base64.
Зачем? Честно говоря, не слышал об этом ничего.

Цитата:
Сообщение от lmikle
2. Дело в том, что очередность прихода пакетов тебе не гарантированна. Поэтому придется кусочки складывать как есть (нумеруя их) и по приходу последнего собирать файл целиком.
Почему не гарантирована? Я же могу отправлять пакеты поочередно, строго в соответствии с тем, как они считываются из FileStream. В этой же последовательности записывать из в файл на сервере. Или существуют еще какие-то подводные камни, о которых мне ничего неизвестно?

Цитата:
Сообщение от lmikle
3. А зачем ты работаешь на таком низком уровне? Возьми TIdFTPClient/TIdFTPServer. Повесь с паролем на нестандартный порт. При желании еще SSL можно прикрутить. Гораздо будет проще.
Нормальные герои всегда идут в обход Давненько как-то пытался написать фтп клиент сервер на них. Больно глючными показались. Да и помимо передачи файлов есть еще кое какие моменты, которые мне реализовать проще с IdTcpServer/Client
Ответить с цитированием
  #4  
Старый 22.01.2011, 13:41
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Делал на скорую руку передачу файлов через WinSock. Столкнулся с проблемой по поводу
Цитата:
Клиент - файл загружается в FileStream, размер файла делится на размер блока(допустим 1000 байт) = получаем количество блоков. Отправляем на сервер количество блоков или размер файла.
Если отправить кол-во блоков, то вовсе не обязательно, что их на сервере будет столько же. Грубо говоря, отправляем так файл в 4000 байт:
1000
1000
1000
1000
На сервере можем получить такую картину:
1000
800
1000
600
600
т.е. уже 5 пакетов.
Так что на пакеты опираться нельзя. Что еще придумать - пока не знаю.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #5  
Старый 22.01.2011, 13:58
evgeny_sh evgeny_sh вне форума
Прохожий
 
Регистрация: 22.01.2011
Сообщения: 4
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
Делал на скорую руку передачу файлов через WinSock. Столкнулся с проблемой по поводу

Если отправить кол-во блоков, то вовсе не обязательно, что их на сервере будет столько же. Грубо говоря, отправляем так файл в 4000 байт:
1000
1000
1000
1000
На сервере можем получить такую картину:
1000
800
1000
600
600
т.е. уже 5 пакетов.
Так что на пакеты опираться нельзя. Что еще придумать - пока не знаю.
Да, про блоки я пожалуй загнул Гораздо надежней считать размер файла - он передается на сервер (ReadBuffer(p^, Size); Client.Socket.Send(p^, Size) Но с реализацией всего этого механизма бьюсь еже третий день, все какая-то херня поручается
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 11:33.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025