Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2004.06.06;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.49 MB
Время: 0.03 c
4-1082818484
gRad
2004-04-24 18:54
2004.06.06
Параметры ф-ий из dll


14-1084638273
666
2004-05-15 20:24
2004.06.06
где взять ACMDialog, ACMWaveIn, ACMWaveOut


3-1084474305
Dmitry Vyacheslavovich
2004-05-13 22:51
2004.06.06
проблема с редактированием связанной таблицы


1-1085655449
Сергей_В
2004-05-27 14:57
2004.06.06
CAPICOM


1-1085126699
ПрогерШу
2004-05-21 12:04
2004.06.06
В чем хранить картинки?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский