Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.06.06;
Скачать: CL | DM;

Вниз

TServerSocket внутри NT- сервиса   Найти похожие ветки 

 
fatman ©   (2004-04-16 00:01) [0]

Всем доброго дня (вечера, ночи).. Есть у меня такая вот проблема : я использую пару ClientSocket и ServerSocket для пересылки пакета... будучи оформленными в два разных оконных приложения (тестовые), они отлично работают и обмениваются пакетами... но мне хочется, чтобы серверсокет был вложен в службу... соответственно я один к одному копирую работающий код в событие уже в сервисе: вот код события

procedure TServerMonitor.ServerClientRead(Sender: TObject;
 Socket: TCustomWinSocket);
Var
 TempStr:String;
 BulkName:String;
 plus,minus,Sun,Dollar:Byte;
begin
{Пакет  Имя+Ship_name*Commodity$Дата-Масса}
 TempStr:=Socket.ReceiveText;
 plus:=pos("+",TempStr);
 Minus:=Pos("-",TempStr);
 Sun:=Pos("*",TempStr);
 Dollar:=Pos("$",TempStr);
 BulkName:=Copy(TempStr,1,plus-1);
 if BulkName="A9" then
  begin
   A9Data.ShipName:=Copy(TempStr,Plus+1,Sun-Plus-1);
   A9Data.Commodity:=Copy(TempStr,sun+1,Dollar-Sun-1);
   A9Data.DateTime:=StrToFloat(Copy(TempStr,Dollar+1,
                                   Minus-Dollar-1));
   A9Data.Weight:=StrToFloat(Copy(TempStr,Minus+1,
                              Length(TempStr)-Minus-1));
   MakeCurrentFolder;
   SaveBulkData(A9File,A9Data);
  end;
 If BulkName="A16" then
  begin
   A16Data.ShipName:=Copy(TempStr,Plus+1,Sun-Plus-1);
   A16Data.Commodity:=Copy(TempStr,sun+1,Dollar-Sun-1);
   A16Data.DateTime:=StrToDateTime(Copy(TempStr,Dollar+1,
                                   Minus-Dollar-1));
   A16Data.Weight:=StrToFloat(Copy(TempStr,Minus+1,
                              Length(TempStr)-Minus-1));
   MakeCurrentFolder;
   SaveBulkData(A16File,A16Data);
  end;
  ShowMessage("Получено = "+TempStr + #10
              + "Имя Файла - "+A16File);
end;

Этот код обработчика события от клиента один к одному работает в приложении, но событие не возникает в сервисе (последний showmessage -- то уже чисто контрольный :))  ).
Вопрос в чем :
есть ли какие-то нюансы при размещении серверсокетов в коде NT-службы, которые мне следует учесть, или же их там вообще не использовать? В чем нескладуха этого подхода?


 
Cobalt ©   (2004-04-16 01:13) [1]

Ну, насчёт  ShowMessage - разрешить сервису взаимодействовать с десктопом.А лучше, вместо этого - писать в к-нито журнал.


 
Verg ©   (2004-04-16 01:29) [2]

Насчет сервиса - тут надо смотреть (знать) как ты сделал этот сервис-приложение. Потому как в тривиальном случае, по пути наименьшего сопротивления - все работает. Проверено.


> TempStr:=Socket.ReceiveText;


И дальше ты стопудово уверен, что принял ровно столько информации за один OnRead, сколько расчитывал принять - ни больше, ни меньше.... - Заблуждение.

Такой подход может создавать видимость правильной работы только в "тепличных условиях". Например, локальной сети или хоста. Есть не один десяток причин, от тебя независящих, по которым порции информации в протоколе TCP могут приходить "непредсказуемого" размера из того потока, который тебе передается собеседником. Он так устроен, он поточный, т.е. способ дробления информации на пакеты - это его выбор. Он (TCP) должен гарантировать только последовательность и неискаженность предаваемой информации, либо сообщить о невозможности выполнения этих гарантий разрываом соединения. Все! - Ни порционность, ни время доставки он гарантировать НЕ может и нельзя расчитывать на то, что изначально не обещано!
И если у вас получается проехать весь город за 20 минут на автомобилях колонной в три часа ночи (ненагруженный LAN), то вы же не будете обещать добраться этим же маршрутом в этом же городе за те же 20 минут но в 3 часа дня, да еще и чтоб вся эта колонна добралась до места так же почти одновременно.

Это может напоминать трубу "общего пользования", по которой переливают ведро с водой. Тот, кто заливает воду в трубу через воронку временами должен подождать пока в воронке освобдится место. На появление места (OnWrite) в этой воронке он реагирует подливанием следующей порции "до краешков", а может и нет, его могут отвлечь от этого занятия (Multitasking), и тогда в потоке образуются пустоты. Но в основном эти пустоты образуются по причине всяких засоров (заторов) в трубе, которые иногда исчезают и временами "вода" на приемной стороне (OnRead) просто хлещет фонтаном, хотя еще миг назад она, может быть, только вяло капала....


 
Digitman ©   (2004-04-16 09:12) [3]


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


никаких особых нюансов

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

эти сообщения, в конечном итоге, обрабатываются "внутренностями" компонентов и уже "причесанные" должным образом выдаются "наружу" в виде знакомых нам событий OnRead, OnWrite, OnConnect, OnDisconnect, OnAccept, OnError

для того чтобы поступающие от Winsock оконные сообщения могли быть обработаны (т.е. была вызвана оконная ф-ция того или иного окна), необходимо чтобы кодовый поток, создавший окно (а именно -тот  код.поток, в контексте которого был успешно выполнен метод Open), выполнял цикл выборки/диспетчеризации оконных сообщений

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

в случае когда компоненты создаются (с последующим вызовом Open) в контексте основного кодового потока VCL-приложения (по-русски говоря - компонент просто брошен в дизайн-тайм на форму либо создан в ран-тайм в ходе обработки, например, события нажания на кнопку), цикл выборки/диспетчеризации сообщений осн.код.потоку процесса работающего приложения уже организован Борландом в виде тела общеизвестного метода Application.Run ... именно в этом методе крутится постоянный цикл, ожидающий и выбирающий поступающие в очередь сообщения и тут же диспетчерезующий их

в случае когда Open этих компонентов выполняется не в основном , а в некоем доп.код.потоке, на программиста возлагается обязанность самостоятельно организовать цикл выборки/диспетчеризации, ибо это прерогатива самого программиста - Борланд справедливо не делает никаких предположений об алгоритме доп.код.потока и не организует никаких "готовых циклов", как в случае с Application.Run для основного потока

в случае с приложением-сервисом каждый отдельно взятый сервис (точнее - его алгоритм) выполняется в отдельном код.потоке, следовательно, если метод Open компонента выполнен именно в потоке сервиса, то здесь как раз и следует организовать упомянутый цикл.. кр.того, в этом цикле должен присутствовать опрос контроллеров, адресованных системой сервису, иначе сервис не будет реагировать на команды стопа/приостанова/возобновления и т.д. и т.п.

по поводу этого следует явно указать, что различные события объекта-наследника класса TService возбуждаются в различных код.потоках ... так, например, события OnCreate/OnDestroy возбуждаются в осн.код.потоке сервис-приложения, в то время как события OnStart/OnStop/OnExecute - в дополнительном (одно и то же сервис-приложение может реализовывать более одной службы, и для каждой службы создается отдельный объект-наследник TService + отдельный доп.код.поток)

с учетом того, что Борланд, по образу и подобию обычным VCL-приложениям, реализовал для сервис-приложений метод ServiceApplication.Run, следует сделать вывод, что если метод Open упомянутых компонентов вызван в ходе обработки события OnCreate, то никаких спец.мер по организации цикла выборки/диспетчеризации принимать не нужно - все будет работать точно так же, как и в случае с обычным приложением ...

если метод Open вызывается в обработчике OnStart, то обработчик OnExecute либо не должен быть назначен вообще либо тело этого обработчика должно содержать примерно след.цикл :

procedure TMyService.ServiceExecute(Sender: TService);
begin
// метод Open вполне м.б. вызван и здесь, если это требуется
 while not Terminated do
   ServiceThread.ProcessRequests(True); //здесь происходит ожидание/выборка/диспетчеризация всех сообщений, адресованных потоку и его окнам
end;

p.s. еще раз заострю внимание, что все изложенное имеет отношение и смысл только в случае работы упомянутых трансп.компонентов в режиме non-blocking, в блокирующем же режиме компоненты сами по себе не создают никаких окон


 
fatman ©   (2004-04-16 22:44) [4]

Огромнейшее спасибо за обстоятельные ответы...
Сегодня я обнаружил другую интересную штуку...
Писал Digitman, что при размещении метода Open сокета в событии OnCreate все должно быть путем... собсно, я так и делал, просто не писал про это в своем предыдущем посте... А нюянс оказался в следующем :
 Принимаемые пакеты с другой стороны серверсокету шлет клиентсокет, которого я тоже (там) разместил в службе... Так вот, что оказалось, на стороне клиента отсылка идет, контроль соединения TCP показывает, что connection установлен, пакет посылается (тоже контролировал это), но сервер его не принимает.
А если клиента разместить в обычном оконном приложении, а не в службе, то вышеупомянутый код сервера начинает принимать эти пакеты, ни один не пропуская.... вот...
Какая-то для меня непонятка в этом... Сервер-служба одна и та же, клиент в службе : не работает, клиент в приложении : работает... Думаю, объяснять не надо, что клиент из службы в приложение переносится по методу ctrl-c + ctrl-v :)))...
Собственно вот сам клиент

procedure TMonitor.TimerTimer(Sender: TObject);
Var
   s1,s2:Variant;
   Sent:Integer;
   tosend:String;
   H:HWND;
begin
H:=FindWindow("ThunderRT6FormDC",nil);
IF H<>0 then
 begin
 If Not Client.Active then
  Client.Open;
 AdoConnection.Connected:=True;
 AdoTable.Active:=True;
 LastWeight:=Weight;
 AdoTable.Requery;
 Weight:=AdoTable.FieldValues["Total"];
 S1:=AdoTable.FieldValues["Unit ID"];
 S2:=AdoTable.FieldValues["Commodity ID"];
 If Weight<>LastWeight then
  begin
  ToSend:="A16"+
           "+"+S1+
           "*"+S2+
           "$"+FloatToStr(Now)+
           "-"+IntToStr(Weight);

   Sent:=Client.Socket.SendText(ToSend);
   end;
 AdoConnection.Connected:=False;
 AdoTable.Active:=False;
 end
end;

Код сервера изложен выше... вот в чем принципиальное различие , чем я шлю серверу пакет - службой или приложением, я не понимаю.... при этом (как я уже говорил) на стороне клиента-службы пакет уходит, но он не приходит в сервер... и приходит, если клиент приложение....
В чем прикол-то?


 
Digitman ©   (2004-04-18 11:19) [5]

для проверки отключи на время алгоритм Нагла

см. SetSockOpt(), опция TCP_NODELAY

в целом же говоря, кл.алгоритм у тебя некорректен

в неблок.режиме успешное выполнение строчки

Client.Open

отнюдь не означает успешное установление соединения

фактом такового следует считать искл-но факт возбуждения события OnConnect

признаком же допустимости вызывать send-метод явл-ся факт возбуждения события OnWrite

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



Страницы: 1 вся ветка

Текущий архив: 2004.06.06;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.05 c
3-1084537112
vaa
2004-05-14 16:18
2004.06.06
BLOB handle


4-1082111100
sapsi
2004-04-16 14:25
2004.06.06
Получение хэндлов окон Word и Exсel


3-1084195613
karburator
2004-05-10 17:26
2004.06.06
Текущая дата в FB1.5 / IB


14-1084771271
Dimman
2004-05-17 09:21
2004.06.06
Linux и MailSlotы


4-1082601486
DeHuC
2004-04-22 06:38
2004.06.06
TWebBrowser + эмуляция нажатия TAB