Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.03.2013, 18:28   #1
alextrof94
Форумчанин
 
Регистрация: 16.03.2013
Сообщений: 599
По умолчанию TClient~ServerSocket. Передача текста/файла (чередование).

Уже неделю бьюсь над проблемой передачи файла и текста по очереди, то-есть:
1. Клиент отсылает запрос на сервер о передаче файла (бинарного)
2. Сервер отвечает (старт или ошибка) и начинает посылать файл (если старт).
3. Клиент получает сообщение о начале (или неудаче) отправки файла и переходит в режим получения потока.
4. Получает файл (или при дисконнекте), переходит обратно в режим получения текстовых команд.

Собственно таким решение вижу я (или же саму проблему). У меня не получается организовать это правильно. Файл либо не передается, либо передается несколько килобайт. Файл бинарный, собственно в этом и заключается проблема, с текстовиками у меня все работало, но там и прием осуществлялся через string.

Функции клиента, "как я это делаю" у меня нет, потому что я пробовал много разных вариантов и в данном случае в программе сохранился не рабочий.

Функция сервера, собсно, само получение команды и отправка потока:
Код:
procedure TFormMain.SSClientRead(Sender: TObject; Socket: TCustomWinSocket);
  var s,login,pass:ansistring; text,cmd:string;
 FS: TFileStream;
begin
  s := Socket.ReceiveText; //s=cmd#text#
  cmd:=Copy(s,1,Pos('#',s)-1);
  Delete(s,1,Pos(';',s));
  text:=Copy(s,1,Pos('#',s)-1);  
if cmd='DOWNLOADCOUNTER' then
  begin
    Mlog.Lines.Insert(0,'DOWNLOADCOUNTER IP: '+socket.RemoteAddress);
    s := 'DOWNLOADCOUNTERBACK#ST#'; //Start
    socket.SendText(s);
    FS:=TFileStream.Create(abspath+'counterplus.exe', fmOpenRead);//abspath - string с путем программы(для ини-файлов создал).
    try
      Socket.SendBuf(FS.Size, SizeOf(FS.Size));
      Socket.SendStream(FS);
    except
      FS.Free;
    end;
    Exit;
  end;
end;
alextrof94$gmail.com
alextrof94 вне форума Ответить с цитированием
Старый 16.03.2013, 19:48   #2
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
По умолчанию

Привер передачи файла. Посмотри, может, что сможешь перетащить к себе.
Вложения
Тип файла: zip Передача файлов через Socket.zip (126.6 Кб, 99 просмотров)
Shouldercannon вне форума Ответить с цитированием
Старый 16.03.2013, 20:09   #3
alextrof94
Форумчанин
 
Регистрация: 16.03.2013
Сообщений: 599
По умолчанию

Цитата:
Сообщение от Shouldercannon Посмотреть сообщение
Привер передачи файла. Посмотри, может, что сможешь перетащить к себе.
Это передача НЕ БИНАРНЫХ файлов. И да. Такой способ у меня работал, только вот БИНАРНЫЕ файлы этим способом не передать...
alextrof94$gmail.com
alextrof94 вне форума Ответить с цитированием
Старый 17.03.2013, 17:58   #4
phomm
personality
Старожил
 
Аватар для phomm
 
Регистрация: 28.04.2009
Сообщений: 2,882
По умолчанию

Всё передаётся, просто размер буфера для передачи потока с помощью этих компонент - 8 кб, и надо передавать как раз по 8 кб, а потом собирать вместе.
Вот в TTcpServer TTcpClient вроде нет таких проблем, но там немного посложнее организованы прочие операции.
Вот ещё темочка с примером http://programmersforum.ru/showthread.php?t=225551
phomm вне форума Ответить с цитированием
Старый 18.03.2013, 03:08   #5
alextrof94
Форумчанин
 
Регистрация: 16.03.2013
Сообщений: 599
Сообщение С проблемой разобрался.

Скажу одно - с3.14жжено. Я просто решил полностью перейти на потоки, и ОЧУДО, я нашел то, что искал.
Пришлось конечно доводить до ума, но все таки все работает нормально.
Закомментированый код сервера:
Код:
var 
    fs: tmemorystream;
    loadingstream:boolean;
    sizehost,sizelocal:int64;
    lastuptime:string;
...

procedure TFormMain.SSClientRead(Sender: TObject; Socket: TCustomWinSocket);
  var s,text,cmd:string;
  buf: pointer;
  L: Integer;
begin
  if not loadingstream then //если не режим принятия файла (т.е. если сейчас режим принятия строки)
  begin
    s := socket.ReceiveText; //получаем строку с командой и текстом
    cmd:=copy(s,1,pos('#',s)-1);
    delete(s,1,pos('#',s));
    text:=copy(s,1,pos('#',s)-1);
    if cmd= 'UPTIME' then //если команда на запрос аптайма, посылаем последний известный аптайм (вычисляется в левой функции)
    begin
      //на самом деле тут может быть любая команда и любой текстовый ответ, главное, текст ответа не должен содержать разделительного знака (тут решетка, возможно допускается #13 и подобные спец символы).
      Mlog.Lines.Insert(0,'UPTIME IP: '+socket.RemoteAddress);
      s:='UPTIMEBACK#'+lastuptime+'#'; //создание строки "cmd#text#"
      socket.SendText(s); //отправка
    end;
    //передача подготовка
    if cmd= 'GIVEFILE' then
    begin
      fs:=tmemorystream.create;
      fs.LoadFromFile(abspath+'counterplus.exe');
      s:='FILE#'+inttostr(fs.Size)+'#'; //пересылаем размер файла (и ждем команду старт)
      socket.SendText(s);
      fs.free;
    end;
    //передача
    if cmd= 'FILESTART' then
    begin
      fs:=tmemorystream.create;
      fs.LoadFromFile(abspath+'from.exe'); //abspath - путь к программе получаемый getfiledir(application.exename) при старте, можно удалить. from.exe файл, требующий передачи клиенту.
      Socket.SendStream(fs);
    end;
    //передача удалась
    if cmd= 'FILEEND' then
    begin
      Mlog.Lines.Insert(0,'DOWNLOAD COMPLITE IP: '+socket.RemoteAddress);
      {тут приведен пример обратной передачи файла, если раскоментировать, то после передачи файла, сервер запросит этот же файл обратно и сохранит его в back.exe
      s:='GIVEFILE##'; 
      socket.SendText(s);}
    end;
    //прием файла подготовка
    if cmd='FILE' then
    begin
      sizehost := strtoint(text); //получение размера файла
      loadingstream := true; //переключение в режим принятия файла
      sizelocal := 0; //обнуление размера скачанного файла
      fs := TMemoryStream.Create;
      s:='FILESTART##'; //отправка команды старт
      Socket.SendText(s);
    end;
  end
  else
  begin
  //прием файла
    try
      L := socket.ReceiveLength;
      getmem(buf, L);
      fs.Position := sizelocal;
      L := socket.ReceiveBuf(buf^, L);
      fs.WriteBuffer(buf^, L);
      inc(sizelocal, l);
    finally
      freeMem(buf);
    end;
    if sizelocal = sizehost then //если размер скачанного файла = размеру передаваемого то
    begin
      fs.Position := 0; //возврат к началу потока
      fs.SaveToFile(abspath+'back.exe'); //сохранение потока в файл back.exe (тут идет пример возврата переданного файла)
      fs.free;
      loadingstream := false; //переход в режим приема строки
      sizelocal := 0;
      s:='FILEEND##'; //отправка сообщения о конце передачи.
      Socket.SendText(s);
    end;
  end;
end;
alextrof94$gmail.com

Последний раз редактировалось alextrof94; 18.03.2013 в 03:14.
alextrof94 вне форума Ответить с цитированием
Старый 18.03.2013, 03:08   #6
alextrof94
Форумчанин
 
Регистрация: 16.03.2013
Сообщений: 599
Сообщение продолжение

НЕзакомментированый код клиента (по сути клон сервера, за исключением прогрессбара и передачи того же файла, что и получаем):
Код:
procedure TForm1.CSRead(Sender: TObject; Socket: TCustomWinSocket);
var s,cmd,text:string;
  buf: pointer;
  L: Integer;
begin
  if not loadingstream then
  begin
    s := socket.ReceiveText;
    cmd:=copy(s,1,pos('#',s)-1);
    delete(s,1,pos('#',s));
    text:=copy(s,1,pos('#',s)-1);
    if cmd= 'UPTIMEBACK' then
    begin
      Mlog.Lines.Insert(0,'UPTIMEBACK: '+text);
    end;
    //передача подготовка
    if cmd= 'GIVEFILE' then
    begin
      fs:=tmemorystream.create;
      fs.LoadFromFile(abspath+'dest.exe');
      s:='FILE#'+inttostr(fs.Size)+'#';
      socket.SendText(s);
      fs.free;
    end;
    //передача
    if cmd= 'FILESTART' then
    begin
      fs:=tmemorystream.create;
      fs.LoadFromFile(abspath+'dest.exe');
      Socket.SendStream(fs);
    end;
    //передача удалась
    if cmd= 'FILEEND' then
    begin
      Mlog.Lines.Insert(0,'UPLOAD COMPLITE');
    end;
    //прием файла подготовка
    if cmd='FILE' then
    begin
      sizehost := strtoint(text);
      loadingstream := true;
      sizelocal := 0;
      fs := TMemoryStream.Create;
      s:='FILESTART##';
      Socket.SendText(s);
    end;
  end
  else
  begin
  //прием файла
    try
      L := socket.ReceiveLength;
      getmem(buf, L);
      fs.Position := sizelocal;
      L := socket.ReceiveBuf(buf^, L);
      fs.WriteBuffer(buf^, L);
      inc(sizelocal, l);
    finally
      freeMem(buf);
    end;
    if sizelocal = sizehost then
    begin
      fs.Position := 0;
      fs.SaveToFile(abspath+'dest.exe');
      fs.free;
      loadingstream := false;
      sizelocal := 0;
      form1.ProgressBar1.Position:=0; //сброс прогрессбара
      s:='FILEEND##';
      Socket.SendText(s);
    end;
    form1.ProgressBar1.Position:=round(sizelocal/sizehost)*100; //тут прогрессбар обновляется, при передаче маленьких файлов на большой скорости не заметно. Работает корректно 100%.
  end;
end;
alextrof94$gmail.com

Последний раз редактировалось alextrof94; 18.03.2013 в 03:15.
alextrof94 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
передача сообщений через serversocket и clientsocket virtuhay266 Помощь студентам 1 14.12.2011 22:54
ServerSocket и ClientSocket передача буфера Тутонхамон Работа с сетью в Delphi 5 15.04.2011 13:34
Передача данных StringGrid через ServerSocket - ClientSocket Polotenchik Общие вопросы Delphi 4 18.03.2010 01:42
ClientSocket,ServerSocket передача данных Torvald Работа с сетью в Delphi 3 07.09.2009 03:59
Передача текста файла.... prizrak1390 Общие вопросы Delphi 1 23.06.2008 10:58