Форум: "Сети";
Текущий архив: 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