Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Отправка файла с Indy клиента на Indy сервер


Автор: Диас 26.6.2006, 13:41
Здравствуйте. Необходимо отправить файл с клиента на сервер. Использую Delphi 7 и Indy 9. На клиенте пишу:

Код

procedure TForm2.Button1Click(Sender: TObject);
var
    fstream:tfilestream;
begin
with form1.IdTCPClient1 do
  try
   Connect;
   GetResponse(200);
   WriteLn('RegisterUser '+username);
   fstream:=tfilestream.Create(filename,fmOpenRead);
   WriteStream(fstream,true,true);
   GetResponse(200);
end;


filename берется из OpenDialog'а.

А на сервере обработчик команды RegisterUser имеет вид:

Код

procedure TForm1.IdTCPServer1cmdRegisterUserCommand(ASender: TIdCommand);
var 
    ...
    stream:tstream;
begin
 ...
 CoInitialize(nil);
 stream:=TMemoryStream.Create;
 try
  ASender.Thread.Connection.ReadStream(stream);
  stream.Position:=0;
  image1.Picture.Bitmap.LoadFromStream(stream);
 finally
  stream.Free;
 end;
 ...
end;


Но сервер зависает на строчке 
"ASender.Thread.Connection.ReadStream(stream);"
Может надо как-то передать, что стрим закончен? Или может предварительно отправить размер передаваемого файла?
Кто знает в чем дело, прошу указать на недостатки/ошибки.  

Автор: _hunter 26.6.2006, 13:48
поиском пользуемся:
http://forum.vingrad.ru/index.php?showtopic=42410 

Автор: Диас 26.6.2006, 20:48
Разумеется, это в первую очередь! И только, потому что там нет моего случая, пришлось создать тему! 

Автор: Диас 29.6.2006, 09:06
Уже пробую делать так: взято с примера Indy9Demos, ImageServer. Только пришлось немного переделать, потому что в примере пересылка тоже идет от сервера к клиенту.

Отправка с клиента:
Код

procedure TForm2.Button1Click(Sender: TObject);
var
    filename:string;
    fstream:tfilestream;
begin
 filename:=OpenDialog1.FileName;
 with form1.IdTCPClient1 do
 try
   Connect;
   GetResponse(200);
   WriteLn('File');
    //отправка файла
    fstream:=tfilestream.Create(filename,fmOpenRead+fmShareDenyNone);
    OpenWriteBuffer;
    WriteStream(fstream);
    CloseWriteBuffer;
    Disconnect;
    FreeAndNil(fstream);
    GetResponse(200);
  finally
    Disconnect;
  end;  
end;


На сервере существует CommandHandler - File. Его обработчик:
Код

procedure TForm1.IdTCPServer1cmdFileCommand(ASender: TIdCommand);
var 
    stream:tfilestream; 
begin 
 //прием файла, папка ttt перед приемом пуста
 stream:=TFileStream.Create('c:\ttt\a.bmp',fmCreate); 

  while ASender.Thread.Connection.Connected do
      ASender.Thread.Connection.ReadStream(stream,-1,true);

  freeandnil(stream);
  image1.Picture.LoadFromFile('c:\ttt\a.bmp');
 end;


Проблема 1:
После данной переделки файл отказывается загружаться в Image и даже открываться в Винде, хотя имеет тотже размер и расширение.

Проблема 2:
Как видно из кода сервера, поток читается до тех пор, пока клиент не отсоединится. А мне нужно, чтобы клиент не отсоединялся, чтобы узнал как там все прошло (GetResponse(200)). 

Автор: Romikgy 13.7.2006, 15:01
Цитата(Диас @  29.6.2006,  08:06 Найти цитируемый пост)
Проблема 1:
После данной переделки файл отказывается загружаться в Image и даже открываться в Винде, хотя имеет тотже размер и расширение.

сравни файлы по содержимому, тотал командер это умеет, может просто зануляется файл

Цитата(Диас @  29.6.2006,  08:06 Найти цитируемый пост)
А мне нужно, чтобы клиент не отсоединялся, чтобы узнал как там все прошло (GetResponse(200)).  

не понял что те нужно? 

Автор: Snowy 13.7.2006, 15:11
Сначала нужно передать размер передаваемых данных, чтобы сервер знал, сколько байт ему принимать. 

Автор: Диас 13.7.2006, 20:39
Цитата

не понял что те нужно?


Сервер заканчивает читать поток только после разъединения:
Код

while ASender.Thread.Connection.Connected do
      ASender.Thread.Connection.ReadStream(stream,-1,true);

А мне не надо разъединяться.

Цитата

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

А какое поставить условие? Или где потом на сервере указать сколько байт принимать? 

Автор: Snowy 14.7.2006, 09:21
-1 это и есть читать до дисконнекта.
Хочешь другой результат - задавай размер.
Чтобы его задать, его должен сообщить клиент, ибо серверу абсолютно неизвестен размер файла.

Перед отправкой стрима, отправь 4 байта с длиной файла.
На стороне сервера читай эти 4 байта.
На клиенте отправляй стрим.
На сервере принимай стрим, только вместо -1 указывай принятый размер. 

Автор: Диас 14.7.2006, 09:54
Все сделал, как ты сказал, файл принимается и идентичен по размеру оригиналу, но по содержимому они разные! При открытии их в блакноте у нового файла имеется пустая строка в начале. Щас попробую через Тотал командер. 

Автор: Snowy 14.7.2006, 10:29
Код

procedure TForm1.IdTCPServer1cmdFileCommand(ASender: TIdCommand);
var 
    stream: TMemoryStream; 
    sz: integer;
begin 
  stream := TMemoryStream.Create;
  with ASender.Thread.Connection do
    while Connected do begin
      sz := ReadInteger;
      ReadStream(stream, sz, false);
  end;
  stream.Position := 0;
  image1.Picture.LoadFromStream(stream);
  freeandnil(stream);
 end;

На клиенте соответственно нужно перед отправкой стрима послать размер WriteInteger;

Добавлено @ 10:35 
Цитата(Диас @  14.7.2006,  09:54 Найти цитируемый пост)
При открытии их в блакноте у нового файла имеется пустая строка в начале.
Это потому что ты делаешь WriteStream(fstream,true,true);
А нужно WriteStream(fstream); 

Автор: Диас 14.7.2006, 13:40
Короче, все понятно!  smile Это просто были глюки из-за того, что передаваемых параметров было около 20! Стоило перестать отправлять так много параметров и все заработало. Причем заработало чуть-ли не всеми способами, предложенными здесь!  smile 
Глюки проявляли себя так:
Когда я передавал размер стрима в виде параметра, файл нормально принимался, но потом не открывался, потому что в него, зачем-то, в начало записывались 2 каких-то байта, вместо 2-х нулевых в конце. Если удалить их то файл открывается.
Когда передаешь размер стрима WriteInteger(stream.size), то на приеме (sz:=ReadInteger) sz равняется всегда 218772273. 
Получается, что лучше передавать что-либо не через параметры, а так, Writ'ом.  smile 

Всем спасибо!!!  smile  

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)