Конференция "Сети" » FTP задержка для приема данных.
 
  • Виталий (05.11.13 17:44) [0]
    Доброго всем времени.
    При работе с чистыми сокетами заметил для себя неожиданность:
     Error:='';
    // Открываем порт данных
     if OpenDataPort then begin
    // Просим сервер список каталогов и файлов
       Answer:=SendCommand('LIST '+APath,true);

       Sleep(100);

    //Считываем данные
       ReadAll(SocketDataHandle);
    //закрываем порт данных
       CloseDataPort;
    //приводим считанный ответ к строке
    //Дальше лирика
       Answer:=AsString;
       if Error<>'' then begin Result:=false;end
       else Result:=true;
     end else begin
        Result:=false;
     end;


    Фишка в том что если убрать  Sleep(100); или поставить меньше то данные из порта данных не считываются. Вернее приходит одна строка Total 0
    Я не понимаю, это что так и должно быть - задержка перед считыванием данных?
  • DVM © (05.11.13 18:06) [1]
    Всякие Sleep() в коде - это костыли, которые рано или поздно подведут.


    > Я не понимаю, это что так и должно быть - задержка перед
    > считыванием данных?

    Ну ты что ожидал что тебе сервер немедленно ответит?

    в ReadAll(SocketDataHandle); у тебя что написано то?
  • Виталий (05.11.13 18:17) [2]
    var buf:array[0..512] of byte;siz:ssize_t; rc:Integer;
    begin
    Clear;
    Position:=0;
    repeat
     FillChar(buf,sizeof(buf),0);
     siz:=fprecv(hand,@buf[0],sizeof(buf),0);
     Write(buf,siz);
     rc:=Size;
    until (siz<=0)or(siz<sizeof(buf));
    Result:=Size;
    end;


    Короче считка. Write - метод TMemoryStream.
    Хорошо, сервер мне сразу не ответит, как можно узнать что данные на считывание готовы?
  • DVM © (05.11.13 19:22) [3]
    Можно конечно ioctrlsocket, select
  • Виталий (05.11.13 20:22) [4]
    Ясно. спс.
  • Виталий (06.11.13 11:50) [5]
    Не пойму почему данные не считываются даже если select() отвечает готовностью. Вот код проверки:
    var
         fs:TFDSet;

    begin
    { TODO : Проработать select() }
    WSASetLastError(0);
    FD_ZERO(fs);
    FD_SET(sockHandle,fs);
    Result:=select(0,@fs,nil,nil,nil);
    if Result=-1 then begin
      Result:=WSAGetLastError;
      Error:=SysErrorMessage(Result);
    end else begin

    end;
    end;


    sockHandle сокет, откуда пойдет считка.  select() возвращает единицу, мол сокет готов для считывания, но сразу последующие за этим кодом recv() данные выдает не те что нужно. Sleep() хоть и костыль, но помогает. Всмысле показывает что считывание данных правильное - resv() после него данные выдает правильные.

    Я вообще правильно select() использую?
  • DVM © (06.11.13 11:56) [6]

    > Я вообще правильно select() использую?

    неправильно
  • Виталий (06.11.13 12:08) [7]
    Как правильно?
    В чем моя ошибка?
  • DVM © (06.11.13 12:09) [8]

    > Виталий   (06.11.13 11:50) [5]

    Во-первых, ты не задал интервал, сколько хочешь ждать. Во-вторых, надо проверять множества, как то так будет:

    function CanRead(ASocket: TSocket): boolean;
    var
     fdset: TFDSet;
     tv: TTimeVal;
    begin
     tv.tv_sec := 0;    // тут сколько ждать надо задать
     tv.tv_usec := 0;
     FD_ZERO(fdset);
     FD_SET(ASocket, fdset);
     if select(1, @fdset, nil, nil, @tv) = SOCKET_ERROR Then
       raise TSocketError.Create;
     CanRead := FD_ISSET(ASocket, fdset);
    end;

  • DVM © (06.11.13 12:14) [9]

    > Виталий   (06.11.13 11:50) [5]

    И после select-а не помешает выполнить ioctlsocket(ASocket, FIONREAD, TotalBytesToRead), чтобы узнать сколько у нас там байт готово для чтения в TotalBytesToRead.

    И все это хозяйство select и ioctlsocket надо вызывать в цикле пока не окажется, что данных больше нету для считывания, тогда мы берем все что считали и смотрим это все или нет.
  • Виталий (06.11.13 14:06) [10]

    > пока не окажется, что данных больше нету для считывания

    Т.е. нужно совместить recv и эти функции в цикле считывания?
    Сначала Select() узнаем готовность сокета, потом ioctlsocket - узнаем сколько считать, и сразу же recv для считывания?
  • Виталий (06.11.13 14:07) [11]

    >  ты не задал интервал

    И не нужно. Так и задумано - ждать до посинения в моем случае.

    >  надо проверять множества

    Для чего?
  • DVM © (06.11.13 15:03) [12]

    > Сначала Select() узнаем готовность сокета, потом ioctlsocket
    > - узнаем сколько считать, и сразу же recv для считывания?
    >

    да


    > Для чего?

    то что select не вернула SOCKET_ERROR еще не означает вообще говоря, что сокет доступен для чтения
  • DVM © (06.11.13 15:05) [13]

    > Виталий   (06.11.13 14:07) [11]


    > И не нужно. Так и задумано - ждать до посинения в моем случае.

    И повиснешь если сервер вообще не ответит. Лучше все же поставь интервал.
  • Виталий (06.11.13 15:52) [14]
    Ладно интервал я поставлю. Не в нем вопрос.

    > еще не означает вообще говоря, что сокет доступен для чтения

    Так как определить поступили ли данные для чтения или нет?
    ioctlsocket если я правильно понимаю всего лишь показывает сколько уже готово.
    Как мне определить достоверность поступления данных?
    На данный момент я от FTP сервера получаю фразу total 0 на команду LIST.
    Если ставлю Sleep() то помимо total 0 получаю еще и список файлов из каталога.
    Что получается? что сервер сначала пишет что-то в сокет, потом происходит проход по каталогу и возврат (дописывание) в сокет данных по файлам.
    так?

    Если так то как мне понять что сервер выслал все данные?
  • DVM © (06.11.13 16:39) [15]

    > Если так то как мне понять что сервер выслал все данные?

    Тебе сервер в канал управления должен сказать
  • Виталий (06.11.13 16:50) [16]
    А-а-а... Не трогать данные, пока не придет ответ на саму команду?
    А потом уже либо считывать либо анализировать ошибку, верно?
 
Конференция "Сети" » FTP задержка для приема данных.
Есть новые Нет новых   [118456   +4][b:0][p:0.001]