Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как по UDP (используя Indy) передать файл поблочно. [D7, WinXP]


freak ©   (2004-05-08 19:19:00) 

Привет всем мастерам!

Вопрос такой как по UDP (используя Indy) передать файл поблочно. Вернее проблема в том как его получить.
Не хочу использовать всякие там TMemoryStream или TFileStrem. Что если кому-то взбредет в голову отправить файлик размером этак мегабайт 700, в таком случае оперативке конец. Лучше считывать файл блоками и отправлять их.

Вот здесь листинг клиента и сервера. Отправляем IdUDPClient’ом файлик и на удаленной машине получаем IdUDPServer’ом. Клиент отсылает файл полностью, но сервер принимает его не до конца и не посылает ответ, что файл принят. Где я ошибся не могу понять. Помогите уважаемые мастера разобртся.

Часть кода написана по материалам, опубликованным на этом сайте.

{ЛИСТИНГ КЛИЕНТА (посылаем файл)}
procedure TForm1.Button2Click(Sender: TObject);
var FromF: file;
   NumRead: Integer;
   Buf: array[1..2048] of Char;
   EndPrisnak: String;
   Count: Integer;
begin
UDPClient.Port := 3030;
UDPClient.Host := '192.168.0.1';
UDPClient.Active := True;

AssignFile(FromF, Edit1.Text);
Reset(FromF, 1);

{перед отправкой файла, посылаем удаленной машине команду-предупреждение, что сейчас будем пересылать файл. Команда содержит имя и размер файла}
UDPClient.Send('file#'+Edit1.Text+'#'+IntToStr(FileSize(FromF))+'#');
{Ждем секунду, пока удаленная машина переходит в режим приема файла, хотя этого можно и не делать}
Sleep(1000);

{Передаем файл}
while FilePos(FromF) <> FileSize(FromF) do
begin
  BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
  UDPClient.SendBuffer(Buf, SizeOf(Buf));
  Label1.Caption := 'Отправленно ' + IntToStr(FilePos(FromF)) + ' из ' + IntToStr(FileSize(FromF));
  ProgressBar1.Position := FilePos(FromF) * 100 div FileSize(FromF);
end;  

{После передачи, ждем определенный промежуток времени, пока удаленная машина скажет нам, что прием файла закончен. Время ожидания задается в свойстве IdUDPClient.ReciveTimeout. Если мы не получим ответ “end”, то считаем, что файл не принят}
UDPClient.ReceiveBuffer(EndPrisnak, SizeOf(EndPrisnak));
 if EndPrisnak <> 'end' then
  ShowMessage(‘Прием файла на удаленной машине прошел не удачно.’)
 else
  CloseFile(FromF);

end;

{ЛИСТИНГ СЕРВЕРА (Принимаем файл)}

 private
   { Private declarations }
  Name: string;
  Size: integer;
  Receive: boolean;
  ToF: file;
  NumWritten: Integer;

procedure TForm1.FormCreate(Sender: TObject);
begin
UDPServer.Active:=True;
Receive := false;
end;

procedure TForm1.Writing(AData: TStream; ABinding: TIdSocketHandle);
var s:String;
begin
if FilePos(ToF) < Size then
BlockWrite(ToF, AData, AData.Size, NumWritten);
ProgressBar1.Position := FilePos(ToF)*100 div Size;
Label3.Caption := 'Принято ' + IntToStr(FilePos(ToF)) + ' из ' + IntToStr(Size);
Label4.Caption := 'Размер блока: '+IntToStr(AData.Size);

if FilePos(ToF) = Size then
begin
Receive := false;
CloseFile(ToF);
s := 'end';
ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, s[1], Length(s));
end;
end;

procedure TForm1.UDPServerUDPRead(Sender: TObject; AData: TStream;
 ABinding: TIdSocketHandle);
var Rtext: string; // ???????? ?????
    DataStringStream: TStringStream;
begin
 if Receive then
   Writing(AData, ABinding)

 else
  DataStringStream := TStringStream.Create('');
  DataStringStream.CopyFrom(AData, AData.Size);
  Rtext := DataStringStream.DataString;
  DataStringStream.Free;
  if Copy(Rtext, 0, Pos('#', Rtext) -1)  =  'file' then
    begin
      Delete(Rtext, 1, Pos('#', Rtext));
      Name := ExtractFileName(Copy(Rtext, 0, Pos('#', Rtext) -1));
      Delete(Rtext, 1, Pos('#', Rtext));
      Size := StrToInt(Copy(Rtext, 0, Pos('#', Rtext) -1));
      Delete(Rtext, 1, Pos('#', Rtext));
      Label1.Caption := ‘Размер файла: ‘ + IntToStr(Size) + ' байт';
      Label2.Caption := 'Имя файла: ' + Name;
      AssignFile(ToF, 'C:\' + Name);
      Rewrite(ToF, 1);
      Receive := true;
      Writing(AData, ABinding);
    end;

end;


Anatoly Podgoretsky   (2004-05-09 12:22:00) [1]

TFileStrem не отличается от нетипизированых файлов, только удобнее.
Реализованый протокол по сути не отличается от TCP только медленее из за задержок ожидание на ответа и вероятно менее надежный.


freak   (2004-05-09 01:51:00) [2]

UDP - это принципиально важно. Не могу использовать другой протокол. Тем более если использовать TMemoryStream или TFileStrem то передача проходит нормально. Проблеммы возникают правда если передоваемый файл больше размера буфера IdUDPClient/Server. Но как  уже говорил всякие Stream'ы мне не подходят.


Rouse_   (2004-05-08 20:09:00) [3]

Код не разбирал...
Не желательно передавать данные которые должны быть приняты полностью (в отличие к примеру от звуковых потоков) без искажений при помощи UDP...
Именно для этого есть другие протоколы...


Наверх

Титульная страница Поиск, карта сайта Написать письмо