Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

TSeverThead, TServerSocket [D7, WinXP]


Страницы:   1 2

dozcent ©   (2008-08-07 19:53:00) 

Здравствуйте уважаемые мастера.
Что то у меня не совсем правильно работает мой сервер осованный на TServerSocket. Есть пара вопросов по поводу класса TServerThread. Стоит ли его перегружать внутренними функциями, или лучше сделать большую функцию ClientExecute.
Стоит ли добавлять в класс компоненты, допустим, для связи с бд, или создать их в функции?

Вот код, который работает кривовастенько... Возникают ошибки, прога иногда вылетает, остаются подвешенные потоки,
перестаёт выполнять хранимые процедуры в БД.

constructor TServerThread.Create(CreateSuspended: Boolean; ASocket: TServerClientWinSocket;
 DataBaseName: string; DBUser: string; DBPassword: string);
begin
 inherited Create(CreateSuspended, ASocket);
 List := TStringList.Create;
 LogType := '';
 DataBase := TIBDatabase.Create(nil);
 Transaction := TIBTransaction.Create(DataBase);
 Proc := TIBStoredProc.Create(DataBase);
 Query := TIBQuery.Create(DataBase);
 try
   DataBase.DatabaseName := DataBaseName;
   DataBase.Params.Add('user_name=' + DBUser);
   DataBase.Params.Add('password=' + DBPassword);
   DataBase.LoginPrompt := false;
   DataBase.SQLDialect := 1;
   DataBase.DefaultTransaction := Transaction;
   DataBase.Connected := true;
   Transaction.Active := true;
   Query.Database := DataBase;
   Query.Transaction := Transaction;
   Proc.Database := DataBase;
   proc.Transaction := Transaction;
 except
   on e: Exception do
     LogError('[' + DateToStr(Now) + ']:::::: ThreadCreate::::' + e.Message);
 end;
 List.Add('[' + DateToStr(Now) + ']::: Thread created sucefuly');
end;

procedure TServerThread.ClientExecute;
var
 i, j: integer;
 buf1: array[0..2] of byte;
 c, cz, temp: byte;
 MessTest: TDisplayMesage;
begin
 inherited FreeOnTerminate := TRUE;
 try
   fSocketStream := TWinSocketStream.Create(ClientSocket, ssTimeOut);
   try
     while (not Terminated) and (ClientSocket.Connected) do
     begin
       if (not Terminated) and (not fSocketStream.WaitForData(ssTimeOut)) then
       begin
         List.Add('[' + DateToStr(Now) + ']::: Thread closed by timeout ');
         ClientSocket.Close;
         fSocketStream.Free;
         Free;
       end;
       DevNo := ClientSocket.ReceiveText;
       DevNo := Trim(DevNo);
       List.Add('[' + DateToStr(Now) + ']::: Thread recive number ');
               if DevNo = 'TEST' then
                 ClientSocket.SendText('OK')
               else
       begin
         if DeviceInDB then //function TServerThread.DeviceInDB:Boolean Check board is present =============
         begin
           if UpdateTime then //function TServerThread.UpdateTime:Boolean Check update time      =============
           begin
             CreatePackedge; //procedure TServerThread.CreatePackedge; Getting record for this board ======
             for j := 0 to 18 do //===================== Sending Erase command =============
             begin
               temp := clear_command[j];
               ClientSocket.SendBuf(temp, 1);
             end;
             List.Add('[' + DateToStr(Now) + ']::: Sending erase command ' + DevNo);
             for j := 0 to Length(mess) - 1 do //===================== Sending Messages ==================
               for i := 0 to Length(mess[j].PrepereMasage) - 1 do
                 ClientSocket.SendBuf(mess[j].PrepereMasage[i], 1);
             List.Add('[' + DateToStr(Now) + ']::: Sending packadge ' + DevNo);
             if (not Terminated) and (not fSocketStream.WaitForData(ssTimeOut * 5)) then //================ Waiting For Answer =====================
             begin
               List.Add('[' + DateToStr(Now) + ']::: Closed by time out on recive message count ' + DevNo);
               ClientSocket.Close;
               fSocketStream.Free;
               Free;
             end;
             cz := ClientSocket.ReceiveLength; //================ Reciving Message Count =================
             ClientSocket.ReceiveBuf(buf1, cz);
             List.Add('[' + DateToStr(Now) + ']::: resived message count ' + DevNo);
             if buf1[2] >= MessCount then //================ SetUP update time ======================
             begin
               SetUpUpdateTime;
               logstr := 'Äèñïëåé ïîäêëþ÷èëñÿ è ïîëó÷èë ' + IntToStr(buf1[2]) + ' ôàéëîâ.' + #13#10;
               LogType := 'UpdateOK';
               LogConnection;
             end
             else
             begin
               logstr := 'Äèñïëåé ïîäêëþ÷èëñÿ íî ïîëó÷èë ' + IntToStr(buf1[2]) + ' ôàéëîâ, à íå ' + IntToStr(MessCount + 2);
               LogType := 'TrasferFaild';
               LogConnection;
             end;
           end; //================ Closing Conection =================
           if LogType = '' then
           begin
             logstr := 'Äèñïëåé ïîäêëþ÷èëñÿ, íî âðåìÿ îáíîâëåíèÿ åù¸ íå ïðèøëî.';
             LogType := 'NoTime';
             LogConnection;
           end;
         end
         else
         begin
           MessTest := TDisplayMesage.Create;
           MessTest.CR;
           MessTest.PrepMess;
           for i := 0 to Length(MessTest.PrepereMasage) - 1 do
             ClientSocket.SendBuf(MessTest.PrepereMasage[i], 1);
           List.Add('[' + DateToStr(Now) + ']::: Sending number for device out DB ' + DevNo);
         end;
         if LogType = '' then
         begin
           logstr := 'Ïîäêëþ÷åííîå óñòðîéñòâî îòñóòñòâóåò â áàçå äàííûõ.';
           LogType := 'NoDevice';
           LogConnection;
           ClientSocket.Close;
         end;
         List.Add('[' + DateToStr(Now) + ']::: Connection close It''s OK ' + DevNo);
         LogServerEvents(List);
         ClientSocket.Close;
       end;
     end;
   finally
     List.Add('[' + DateToStr(Now) + ']::: Finnaly ' + DevNo);
     fSocketStream.Free;
     Free;
   end;
 except
   on e: exception do
   begin
     LogError('[' + DateToStr(Now) + ']::: ThreadExecute::::' + e.Message);
     ClientSocket.Close;
     Terminate;
   end;
 end;

end;


Сергей М.   (2008-08-11 08:27:00) [1]


> Тобишь 1 или 17?


Читай ровно столько, сколько осталось прочитать из этих 17-ти ожидаемых байт

запросил к чтению 17, фактически прочитал 2, осталось прочитать 15
запросил  к чтению 15, фактически прочитал 5, осталось прочитаь 10
запросил  к чтению 10, фактически прочитал 1, осталось прочитаь 9
запросил  к чтению 9, фактически прочитал 4, осталось прочитаь 5

и т.д. до тех пор пока "осталось прочитаь" не станет равным 0

Эта логика применима во всех случаях, когда заранее известен размер очередного инф.сообщения, ожидаемого к приему от партнера на данном этапе исполнения протокола инф.обмена.


Slym   (2008-08-11 06:40:00) [2]

Должно получиться чтото типа этого:
procedure TServerClientThreadEx.ClientExecute;
var
 SocketStream:TWinSocketStream;
 Packet:array[0..16] of byte;
 Packet2:array[0..2] of byte;
begin
 try
   SocketStream:=TWinSocketStream.Create(ClientSocket, 30);
   try
     while (not Terminated) and (ClientSocket.Connected) do
     begin
       if not SocketStream.WaitForData(SocketStream.TimeOut) then
        raise Exception.Create('Protocol: timeout');

       ReadBufferEx(SocketStream,Packet,SizeOf(Packet));
       LogServerEvents('Packet Readed');
       if ClientSocket.ReceiveLength<>0 then
         LogServerEvents('Packet fully Readed, but some socket data still avaliable... Error?');

       SetString(IMEI,Packet,SizeOf(Packet));
       ConnectToDb;
       try
         if DeviceInDB then
         begin
          if UpdateTime then
          begin
            CreatePackage;
            SendingMessage;
            if not SocketStream.WaitForData(SocketStream.TimeOut) then
              raise Exception.Create('Protocol: timeout');

            ReadBufferEx(SocketStream,Packet2,SizeOf(Packet2));
            LogServerEvents('Packet2 Readed');
            if ClientSocket.ReceiveLength<>0 then
              LogServerEvents('Packet2 fully Readed, but some socket data still avaliable... Error?');

            if Packet2[2]>=MessCount then
            begin
              SetUpUpdateTime;
              LogConnection(1);
            end else
            begin
              LogConnection(2);
            end;
          end else
          begin
            LogConnection(3);
          end;
         end else
         begin
          SendingMessageToNewDevice;
          LogConnection(4);
         end;
       finally
         DisconnectFromDb;
       end;
       LogServerEvents('We finish Protocol loop');
     end;
     LogServerEvents('We break IO loop');
   finally
     SocketStream.Free;
   end;
 except
   on e: exception do
     LogError('Error: '+e.Message);
 end;
end;


Slym   (2008-08-11 06:16:00) [3]

dozcent ©   (10.08.08 23:26) [21]
Вы имеете в виду такую конструкцию...

почти
procedure ReadBufferEx(SocketStream:TWinSocketStream;var Buffer; Count: Longint);
var
 PBuffer:PByte;
 Readed:integer;
begin
 PBuffer:=@Buffer;
 while Count>0 do
 begin
   readed:=SocketStream.Read(PBuffer^,Count);
   Dec(Count,readed);
   Inc(PBuffer,readed);
 end;
end;


Slym   (2008-08-11 05:33:00) [4]

приведи протокол устройтсва...


dozcent   (2008-08-10 23:53:00) [5]

А в этой функции лучше ставить минимум или максимум?
  readlen := fSocketStream.Read( fRequest[ac],1024 );
Тобишь 1 или 17?


Сергей М.   (2008-08-10 23:45:00) [6]


> FillChar( fRequest, REQUESTSIZE, 0 );


А это вообще нафиг не нужно.


Сергей М.   (2008-08-10 23:38:00) [7]


> Даже для трёх байт такое надо делать?


Да, даже для двух.

Если тебе пообещали налить бутыль и ты ждешь обещанное, то это вовсе не означает,что ее нальют тебе все разом и сей секунд после обещания - тебе ее когда-нибудь обязательно нальют, но вправе наливать ее через заранее неизвестного/меняющегося диаметра воронку и заранее неизвестными порциями.

Так что готовь тару объемом в бутыль и жди пока она наполнится, коль договорились)

Время наполнения и порции, коими наполнение должно происходить, в общем случае тебе не известно)


dozcent   (2008-08-10 23:31:00) [8]

Даже для трёх байт такое надо делать?


dozcent   (2008-08-10 23:26:00) [9]

Вы имеете в виду такую конструкцию...

var
 ac, readlen : integer;
begin
 FillChar( fRequest, REQUESTSIZE, 0 );
 ac := 0;
 repeat
   readlen := fSocketStream.Read( fRequest[ac],1024 );
   ac := ac+readlen;
 until ( readlen = 0 ) or ( ac = REQUESTSIZE );
end;


dozcent   (2008-08-10 23:22:00) [10]

Как реализовать этот аккомулятор и машину состояния?


Сергей М.   (2008-08-10 23:11:00) [11]

И зачем, спрашивается, ковыряться в куче вываленного тобой дерьма, если серьезная ошибка в транспортной логике очевидна уже в первых строках приведенного кода ?

Нет аккумулятора, нет машины состояния - дальнейший разговор лишен смысла.


Сергей М.   (2008-08-10 23:09:00) [12]


> ошибки!!!!!!!!! Которые на экран вылазят


Да по барабану что там у тебя куда-то "вылазит" !

Ошибки в твоей логике начинаются гораздо раньшепо ходу твоего алгоритма !

И рано или поздно они дадут о себе знать !

Пойми ты наконец-то это)


Сергей М.   (2008-08-10 23:07:00) [13]


> В цикле принимать данные, пока не наберёт 17?


В цикле или не в цикле - не важно.

Но если ты ожидаешь от партнера по соединению 17 каких-то байт, то их сначала нужно гарантированно принять.


> cz := ClientSocket.ReceiveLength;


Читай внимательно справку по логике работы этого св-ва - твое понимание этой логики НЕверно.


dozcent   (2008-08-10 23:01:00) [14]

А когда я говорил про "ГИПОТЕТИКУ", я имел в виду, что такой проблеммы сейчас не существует, а вот ошибки!!!!!!!!! Которые на экран вылазят!!!!
И о которых я прошу помощи!!!


dozcent   (2008-08-10 22:58:00) [15]

При чём тут нежелаю, я прошу помощи, что бы сказали что-то конкретное...
Что такое аккомулировать? Чем?
В цикле принимать данные, пока не наберёт 17?
Вы имеете в виду, что получать и посылать данные надо fSocketStream'ом?
Или что?
А какие мысли по поводу ошибки, которая на экран вылазит?


Сергей М.   (2008-08-10 22:49:00) [16]


> как принять их правильно


Их надо аккумулировать.


> 17 байт посылает модем


Какой еще нахрен модем ? Речь в твоем коде идет о сокете как об источнике поточных данных ..


> не до гипотетических ошибок


Какая еще нахрен "гипотетика", если источник в одном углу Тырнета, а приемник совсем в другом ?


> они всегда доходят в 100% случаев


Не надо уже трындеть.

Разнеси свои приемник и передатчик по разным углам Тырнета и твоя логика тут жепотерпит крах.

И вообще - отладчик тебе в руки, коль ты не желаешь слушать что тебе говорят.


dozcent   (2008-08-10 22:26:00) [17]

Да, и ещё....
Непонятное мне явление...
В блоке finally есть обращение к процедуре LogServerEvents('event');
которое в некоторых потоках срабатывает два раза.....


dozcent   (2008-08-10 22:21:00) [18]

Куда, куда - на экран...
Чесно говоря, сейчас не до гипотетических ошибок, эти 17 байт посылает модем неизвесно каким образом, и они всегда доходят в 100% случаев...
Но очень интересно посмотреть как принять их правильно.
сейчасмне нужно что бы ошибки не останавливали работу сервера и не вылазили на экран, я их ловлю во всех функциях, а они вылазят на экран....
И немогли бы вы кратко объяснить принцип удаления потока из памяти в данной схеме?


Сергей М.   (2008-08-10 22:12:00) [19]

О контексте ты не сказал ни слова.


> if cz <> 17 then//если длинна не равна 17, то это не моё
> устройство!!!


С какого перепугу-то ?

Мало ли сколько байт принятов ДАННЫЙ момент времени ?

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


> почему при имеющемся exception у меня вылазит ошибка!


Кудаона у тебя "вылазит" ?


dozcent   (2008-08-10 21:54:00) [20]

Меня больше волнует, почему при имеющемся exception у меня вылазит ошибка!!!!


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо