Конференция "Прочее" » TServerClientThread.ClientExecute; подскажите дубу как правильно?
 
  • kashey © (25.10.18 15:37) [0]
    unit serverthread;

    interface

    uses
     windows, scktcomp, SysUtils, Classes, Forms;

    type
     EServerThread = class( Exception );
     // serverthread это потомок TServerClientThread
     TServerThread = class( TServerClientThread )
       private
         fSocketStream : TWinSocketStream;
       public
         procedure ClientExecute; override;
         // ClientExecute отменяет
         // TServerClientThread.ClientExecute
         // и содержит код, который
         // выполняется при старте потока
     end;

    implementation

    procedure TServerThread.ClientExecute;
    var
     RStr: String;
     TotalStr: String;
    begin
     TotalStr := '';
     inherited FreeOnTerminate := TRUE;
     try
       fSocketStream := TWinSocketStream.Create( ClientSocket,
                                                 100000 );
       // 100000 - это таймаут в миллисекундах.
       try
         while ( not Terminated ) and ( ClientSocket.Connected ) do
         try
           // Тут я читаю данные от клиента
           // Данные могут быть большой длинны, поэтому
           // ответ от клиента приходит несколькими порциями
           // Читаю так:
            FRecvSize:= ClientSocket.ReceiveLength;
            SetString(RStr, PAnsiChar(@FBuffer[0]), FRecvSize);
           
           //по кускам все прекрасно выводится
           //ShowMessage(RStr);
           //А вот собрать в одну переменную и передать дальше в параметром
           //в функцию не получается
           TotalStr :=  TotalStr + RStr; ????
       
           //Видать что-то с доступом с разных потоков связано?
           //ПОДСКАЖИТЕ ПРАВИЛЬНУЮ РЕАЛИЗАЦИЮ.
         except on e:exception do
           begin
             ClientSocket.Close;
             Terminate;
           end;
         end;
       finally
         fSocketStream.Free;
       end;
     except on e:exception do
       begin
         ClientSocket.Close;
         Terminate;
       end;
     end;
    end;
  • Eraser © (26.10.18 01:03) [1]

    > kashey ©   (25.10.18 15:37) 

    не используй эти компоненты. они глючные, устаревшие и не кроссплатформенные.
    см. Indy.
  • Германн © (26.10.18 02:21) [2]

    > Eraser ©   (26.10.18 01:03) [1]
    >
    >
    > > kashey ©   (25.10.18 15:37)
    >
    > не используй эти компоненты. они глючные

    Имхо они просто куплены были папашей Борландом на случайном рынке. Покупка была явно неудачной тратой пяти копеек. :)
  • kashey © (26.10.18 08:22) [3]
    Кажись разобрался с логикой работы этого "безобразия". Получается создается отдельный поток и цикл
    while ( not Terminated ) and ( ClientSocket.Connected ) do

    работает вечно слушая клиента. И понять все ли тебя прислал клиент или какую-то часть невозможно никак, если нет никакого признака начала и конца данных, а их и нет. Поэтому единственный вариант это определить пришедшие данные по внешнему виду, например если это XML, то просто проверить на валидность хотя бы так:
    try
     XML.add(RecvPart)
     XML.Activ := True
     //действия
     XML.Clear;
    except

    end;


    Мне собственно XML и присылают. Вобщем все со скрипом заработало.


    > не используй эти компоненты. они глючные, устаревшие и не
    > кроссплатформенные.
    > см. Indy.


    Вы серьёзно? На другом форуме подсказали выкинуть Indy и использовать это) Я никогда и близко с сетью не работал и потому поверил:)))

    И опять же в Indy10 OnExecute будет крутится вечно, поэтому логика будет та же. А в Indy9 такого не было(наверное работал в основном потоке), OnExecute - заканчивал работу и в конце этого события можно было забрать все данные. У вас кстати есть по этому поводу похожая тема http://pda.delphimaster.net/?id=1539978759&n=18
  • KSergey © (26.10.18 09:03) [4]
    > kashey ©   (26.10.18 08:22) [3]
    > И понять все ли тебя прислал клиент или какую-то часть невозможно никак, если нет никакого признака начала
    > и конца данных, а их и нет. Поэтому единственный вариант это определить пришедшие данные по внешнему виду, например
    > если это XML, то просто проверить на валидность

    А это не зависит от используемых компонент и/или API.

    Это суть работы через сеть, которые я бы описал двумя базовыми принципами:
    - нет признака "достигнут конец данных", "в сети более ничего нет и не будет" по аналогии с "достигнут конец файла"; такой признак следует передавать явно каким-то образом в данных;
    - на клиента данные будут приезжать кусками произвольного размера, разрезанные в любом произвольном месте; нельзя ожидать и нельзя закладываться в алгоритме обработки на клиенте, что будут приходить целиком строки или целиком другие осмысленные куски или куски какого-то (минимального) размера; клиент будет получать всё кусочками произвольного размера, разного размера: 1 байт, три байта, 1039 байт, 126 байт, 4091 байт и т.д.; алгоритм обработки данных на клиенте должен быть готов к такому.

    Удивительно, кстати, что ни в одной книжке про работу с сетью лично мне вот этого написанного в явном виде - не попадалось. Хотя это база и суть в подходах организации логики сетевых приложений. И это первое, обо что ударяешься и долго не можешь понять. Принять это тоже не сразу удаётся, кстати.
  • kashey © (26.10.18 09:21) [5]

    > Удивительно, кстати, что ни в одной книжке про работу с
    > сетью лично мне вот этого написанного в явном виде - не
    > попадалось. Хотя это база и суть в подходах организации
    > логики сетевых приложений. И это первое, обо что ударяешься
    > и долго не можешь понять. Принять это тоже не сразу удаётся,
    >  кстати.

    Я с этим столкнулся неделю назад, и ждал прямой логики (что послал, то и получил в целом и полном виде).
  • kashey © (26.10.18 10:41) [6]
    Серьёзно вы меня озадачили информации о глючности этих компонент. Хотя работает пока нормально. Но всёж пробую запасной вариант на Indy.
    Чтение данный от клиента адаптировал в TidTCPServer, а вот как послать данные с него клиенту не получается.

    с глючных компонент слал так:
    procedure TMyServer.SendCommand(const Cmd: string; ConnNo: Integer);
    begin
     {TServerSocket}
     FServerSocket.Socket.Connections[ConnNo].SendText(Cmd + #0);
    end;



    Реализация клиента не доступна и соответственно как он обрабатывает данные тоже не известно
    но работало по варианту выше.

    а вот эквивалент на Indy этой процедуре не найду.

    ib: TIdBytes;

    Cmd := 'my command' + #0;
    SetLength(ib, Length(Cmd));
    Move(Cmd[1],ib[0],Length(Cmd));
    AContext.Connection.IOHandler.Write(ib);



    пробовал и в  начало ib писать длинну команды в байтах, хотя по идее она должна обрабатывать клиентом признаком конца строки как тут:
    FServerSocket.Socket.Connections[ConnNo].SendText(Cmd + #0);

  • kashey © (26.10.18 11:50) [7]

    > а вот эквивалент на Indy этой процедуре не найду.

    Извиняюсь, достаточно слать сразу строку
    AContext.Connection.IOHandler.Write(Str);
    и AContext.Connection.IOHandler.InputBuffer до конца не дочитовал с прошлой команды и привет - все сыпалось при новом чтении.

    И коду в 5 раз меньше на Indy стало, так серьезно от тех компонент лучше отказаться?
  • Германн © (30.10.18 01:52) [8]

    > KSergey ©   (26.10.18 09:03) [4]

    > Удивительно, кстати, что ни в одной книжке про работу с
    > сетью лично мне вот этого написанного в явном виде - не
    > попадалось.

    Насчёт книжек сказать ничего не могу. Но Франсуа Пиетт (автор ICS) в своих публикациях это упоминал часто. Возможно именно потому, что он работал с сетью наиболее родным способом. Т.е. асинхронным.
    Добавлю что я уже много лет убеждаю новичков, которые работают с СОМ-портом, что драйвер компорта отнюдь не обязан отдавать им всё и сразу. И это тоже не описано в книжках.
 
Конференция "Прочее" » TServerClientThread.ClientExecute; подскажите дубу как правильно?
Есть новые Нет новых   [118488   +59][b:0][p:0.002]