•  

ГлавнаяIndyЧастые вопросы по Indy → TCPServer, TCPClient медленная закачка файлов на сервер

Создано: 24.05.2014 23:20:30 · Исправлено: 24.05.2014 23:20:30 · Прочтений: 1715

Здравствуйте! Есть такая проблема: Сервер, клиент на TCPServer, TCPClient. Если отправлять файл от клиентов (файл зашивается в TMemoryStream) к серверу, то файлы в десятки метров летят на ура, и аккуратно сохраняются на диск, но если отправлять данные нескольким клиентам с сервера, то все клиенты подвисают. Данные, конечно, в результате приходят, но в гораздо больший промежуток времени. По сути проблема даже не в количестве клиентов, и одному клиенту сервер посылает данные гораздо дольше чем чем их сам принимает. Может быть, и у клиента создавать отдельный поток для сервера, хотя зачем он нужен ведь сервер один? Методы приёма и передачи на обеих сторонах реализованы одинаково.
Без примера кода сложно что-либо советовать.
Это в онАкцепт сервера.

repeat
      sum_size:=0;
      DataBuf.Clear;
      count_rec:=ClientSocket.ReceiveBuf(ClientID,SizeOf(ClientID),0);
      if(count_rec<=0)then Break;// если при блокирующем соединении покет не получен то выходим нафиг
      form1.Memo1.Lines.Insert(0,Name Client:+ClientID.Clientname);//выводим имя клиента
      case ClientID.mode of
        mgetdata://передаем данные с которыми в пинципе знаем что делать
          begin
            if(buf_base.getStreamSize>0)then begin
              ClientID.mode:=mgetdata;
              ClientID.DataSize:=buf_base.getStreamSize;
              ClientSocket.SendBuf(ClientID,SizeOf(ClientID));//одобряем отправку
              buf_base._DataStream.Position:=0;
              ClientSocket.SendStream(buf_base._DataStream);//отправляем
            end else begin
              ClientID.mode:=mnone;//не одобряем
              ClientSocket.SendBuf(ClientID,SizeOf(ClientID));
            end;
          end;
        msetdata://получаем теже данные но уже нам шлют клиенты
          begin
              ClientID.mode:=msetdata;
              DataSize:=ClientID.DataSize;
              ClientSocket.SendBuf(ClientID,SizeOf(ClientID));
              sum_size:=0;
              try
                getmem(buf,1024);
                DataBuf.Clear;
                DataBuf.Position:=0;
                while ClientSocket.Connected do begin
                  count_rec:=ClientSocket.ReceiveBuf(buf^,1024,0);
                  inc(sum_size,count_rec);
                  DataBuf.Write(buf^,count_rec);
                  if((DataSize=sum_size)or(count_rec<=0))then break;
                end;
              finally
                freemem(buf);
                if(DataBuf.Size>0)then begin
                  buf_base._DataStream.Clear;
                  buf_base._DataStream.Position:=0;
                  buf_base._DataStream.Write(DataBuf.Memory^,DataBuf.Size);
                end;
              end;
          end;

      end;
    until not ClientSocket.Connected;
  finally
    ClientSocket.Disconnect;
    DataBuf.Free;
  end;
  form1.Memo1.Lines.Insert(0,Client disconnected);
end;





Это на строне клиента!кнопка на прием!


procedure TForm1.btn1Click(Sender: TObject);
var
  buf:pchar;
  DataSize,sum_size,count_rec:integer;
  scat,scomname,sspa:string;
  rlencm,rlenln:Real;
begin
  with TCPClient do begin
  ClientID.mode:=mgetdata;
  SendBuf(ClientID,SizeOf(ClientID));//отправляем запрос на закачку
  ReceiveBuf(ClientID,SizeOf(ClientID));//получаем разрешение и размер данных
  if(ClientID.mode=mgetdata)then begin
    try
      getmem(buf,1024);
      sum_size:=0;
      buf_base._DataStream.Clear;
      Form1.pb1.Position:=0;
      while Connected do begin
        count_rec:=ReceiveBuf(buf^,1024,0);
        inc(sum_size,count_rec);
        buf_base._DataStream.Write(buf^,count_rec);
        Form1.pb1.Position:=Round(1000*(sum_size/ClientID.DataSize));
        if((ClientID.DataSize=sum_size)or(count_rec<=0))then break;
      end;
      finally
        freemem(buf);
      end;
    end;
  end;
end;


На передачу

procedure TForm1.btn2Click(Sender: TObject);
var sizebuf:Integer;
begin
  if(TCPClient.buf_base._DataStream.size>0)then
  with TCPClient do begin
      buf_base._DataStream.Position:=0;
      ClientID.mode:=msetdata;
      ClientID.DataSize:=buf_base._DataStream.Size;
      SendBuf(ClientID,SizeOf(ClientID));
      sizebuf:=ReceiveBuf(ClientId,SizeOf(ClientID));
      if(sizebuf<=0)or(ClientID.mode<>msetdata) then Exit;
      SendStream(buf_base._DataStream);
    end;
end;


TCPClient,TCPServer чуть чуть расширены,но на их функционал это не влияет.

type TPackage=record        //запись для хранения информации о клиенте
  RIDclient  : integer;    // некий идентификатор
  Clientname  : string[100];// имя клиента
  mode        : TModes;    // режим работы
  DataSize    : integer;    //размер посылемых данных
  command    : string[255];
  info        : string[200];
end;

ClientID:TPackage;

type Tbase=class
  private
    buf_str  : TMemoryStream;

buf_base:Tbase;
Код посмотрел и попробовал - всё отлично работает, хотелось бы узнать какие у вас свойства TcpServer и TcpClient (я использовал значения по-умолчанию и выставил только порт)?
И ещё, в OnAccept сервера код неполный и непонятно зачем там цикл repeat-until (я его выкинул, как ненужный)?
И ещё, в OnAccept сервера код неполный и непонятно зачем там цикл repeat-until (я его выкинул, как ненужный)
Это для того чтобы каждый раз не конектиться, а держать клиента постоянно в этом цикле пока он не отсоединится.Потому как onAccept срабатывало тока в момент соединения,хотя я может что-то не так делаю?!
Сервер:
LocalHost := localhost;
LocalPort := 5000;
BlockMode := bmThreadBlocking;
Клиент:
BlockMode := bmBlocking;
RemoteHost := localhost;
RemotePort := 5000;

Код посмотрел и попробовал - всё отлично работает
Т.е. в обоих направлениях с одной скоростью да? А несколько клиентов пробовали?
Пробовал несколько клиентов:
посылал файл серверу с одного клиента, а потом 10 клиентов забирало этот файл каждую секунду - всё ок.

Вопрос: зачем держать клиента на связи?

Если есть возможность лучше этого не делать, по крайней мере не при использовании компонентов TTCPServer, TTCpClient.
Ну если я за сеанс с десяток файлов захочу передать и еще 100 записей из базы,без цикла не обойтись.
Если есть возможность лучше этого не делать, по крайней мере не при использовании компонентов TTCPServer, TTCpClient.
Какие компоненты лучше всего использовать?
Юзал TClientSocket/TServerSocket там пакеты странным образом пропадали,не все доходили.
Сложно ли будет перекрутить щас все на indy, потому как читал что совершенно разные методы работы с ними?
Я пробовал использовать разные компоненты, в том числе и Indy.
Для каких-то задач Indy подходят идеально, однако при решении серьёзных задач (например, работе в кластерной конфигурации) и с большим количеством запросов к серверу Indy нормально не заработал (просто не смог работать на кластере).
Поэтому я стал использовать библиотеку Synapse http://synapse.ararat.cz/doku.php/

Смотрите сами, решайте сами.