Форум: "Начинающим";
Текущий архив: 2006.12.10;
Скачать: [xml.tar.bz2];
Внизсокеты и web service Найти похожие ветки
← →
Lesorub © (2006-11-16 18:34) [0]Вот у меня в сетке есть web-сервер (апач на winnt). Хотелось бы чтобы web service на нем, при обращении клиента, брал с другого сервера в сетке (где БД) данные. Для этого я попробовал использовать ClientSocket поместив его в Web-module web service"а, как это делается в обычных приложениях. Компиляция прошла без проблем, но при запросе программки-клиента, когда происходило событие ClientSocket.Open, выскочила ошибка Access Violation at address такого-то in module таком-то. Read of address такой-то. И информации толком нигде нет по этой теме, в общем, плз, very need help )
← →
Lesorub © (2006-11-16 19:55) [1]Может стоит Websnap попробовать
← →
Lesorub © (2006-11-16 20:20) [2]ClientSocket.Open конечно же выполняется в web service
← →
Anatoly Podgoretsky © (2006-11-16 20:45) [3]> Lesorub (16.11.2006 18:34:00) [0]
> Access Violation at address такого-то in module таком-то. Read of address такой-то
Это все что сообщило, тогда дело плохо.
← →
Lesorub © (2006-11-16 20:57) [4]Почему же плохо? И никакого решения для такой ситуации нет?
← →
Anatoly Podgoretsky © (2006-11-16 21:37) [5]> Lesorub (16.11.2006 20:57:04) [4]
Потому что это шифровка, по ней никаких выводов сделать нельзя.
← →
Lesorub © (2006-11-16 21:46) [6]Это да, а каким-либо другим способом запустить сокет на стороне сервера, нет? Может webmodule в принципе не совместим с сокетами? Хотя это, честно говоря, было бы странно.
← →
Суслик © (2006-11-16 21:52) [7]
> Почему же плохо? И никакого решения для такой ситуации нет?
У тебя явная ошибка в программе.
Вообще адреса, указанные в сообщении достаточно информативны. По ним можно понять (не всегда, правда), из какого исполняемого модуля (не путать с модлями дельфи) было некорректное обращение. ДЛя просмотра всех загруженный модулей для твоей программы ты можешь использовать утилиту processexplorer из www.sysinternals.com.
А вообще - скачай себе jedi (ищи на www.sourceforge.net) и вставь логирование стека ошибок при исключении. Очень полезная весчь. Денек поразбираешься с jedi, зато потом подобные ошибки будешь находить значительно проще.
У jedi есть пример в jcl\experts\debug\dialog\ExceptDlg.pas как получить стек вызовов при исключении. Но это форма. Тебе никто не мешает самому вызвать JclLastExceptStackList в своем сервисе.
← →
Lesorub © (2006-11-16 22:11) [8]Спасибо, надо попробовать. Но топик пока не закрываем :-)
← →
Суслик © (2006-11-16 22:16) [9]Попробуй.
Дельфи 2006 пользуется именно jedi для построения стека вызовов функций. Там, правда, много мусора. Некоторые функции вроде бы не должны включаться, но включаются - возможно это связано с тем, что я плохо знаю asm, и как следствие функции все-таки должны включаться. Но, все функции через которые прошел вызов в стеке будут. Кроме некоторых из vcl.
Все же, вполне информативно.
← →
Lesorub © (2006-11-16 22:33) [10]На всякий случай дополнительная информация, упрощенный вариант кода web-сервиса:
{ то что в модуле с описанием TWebModule1 = class(TWebModule), т.е. "главный" модуль }
function TWebModule1.Conn: String; //моя функция
begin
Socket1.Open; { <--ошибка происходит здесь, причем сокет заранее настроен как надо }
Conn:="ok";
end;
procedure TWebModule1.WebModuleDestroy(Sender: TObject);
begin
Socket1.Close;
end;
//=======
//а это из модуля с обработчиком запроса
type
TPage = class(TInvokableClass, IPage)
function Base(Start: boolean): String; stdcall;
end;
...
//обработчик, выполняемый при запросе клиентской программки
function TPage.Base(Start: boolean): String;
var
Post:TStrings;
begin
Result:=WebModule1.Conn;
end;
// и стандартно инициализация
initialization
InvRegistry.RegisterInvokableClass(TPage);
Итак если все без ошибок то, результатом должно быть соединение с сервером и значение переменной = "ok"
← →
Lesorub © (2006-11-17 05:43) [11]В обычном приложении, НЕ web-сервисе, без проблем работает, а в web-сервисе вышеописанная ошибка
← →
MikePetrichenko © (2006-11-17 06:34) [12]
> Вот у меня в сетке есть web-сервер (апач на winnt). Хотелось
> бы чтобы web service на нем, при обращении клиента, брал
> с другого сервера в сетке (где БД) данные. Для этого я
> попробовал использовать ClientSocket поместив его в Web-
> module web service"а, как это делается в обычных приложениях.
> Компиляция прошла без проблем, но при запросе программки-
> клиента, когда происходило событие ClientSocket.Open, выскочила
> ошибка Access Violation at address такого-то in module таком-
> то. Read of address такой-то. И информации толком нигде
> нет по этой теме, в общем, плз, very need help )
Даже полную цитать привел...
Большего бреда не читал. Это же надо так извратиться. А чем Apach + PHP + MySQL (FB/MSSQL/Oracle) не устраивает?
Все уже написано до нас.
← →
MikePetrichenko © (2006-11-17 06:47) [13]
> В обычном приложении, НЕ web-сервисе, без проблем работает,
> а в web-сервисе вышеописанная ошибка
Да, и вдогонку. Ты его как что лепишь? Как MOD для Apach или как cgi приложение?
← →
Сергей М. © (2006-11-17 08:10) [14]
> Socket1.Open; { <--ошибка происходит здесь, причем сокет
> заранее настроен как надо }
Это означает, что объект Socket1 не существует.
← →
Lesorub © (2006-11-17 16:01) [15]MikePetrichenko, конечно все уже есть, но цель в том чтобы delphi изучить получше в этом плане. Apach + PHP + MySQL это конечно хорошо, и в нормальных работах так и надо делать, но моя цель повторюсь delphi поизучать, так сказать, под разными углами. И все бы хорошо, только с этой проблемой сложность, вот и хочется разобраться.
Все это делается в виде cgi.
Сергей М., если честно, то не понятно почему он может не существует, если не трудно, объясните подробней, плз. )
← →
Сергей М. © (2006-11-17 16:05) [16]
> не понятно почему он может не существует
Ну откуда ж мне знать ? То ли не создан он, то ли потерян ...
Впрочем объект-то может и существует, но вот поле Socket1 почему-то содержит nil или "мусор" ... Проверь это сам ...
← →
Lesorub © (2006-11-17 16:27) [17]А как это проверить? дебаггером?
← →
MikePetrichenko © (2006-11-17 16:53) [18]
> Все это делается в виде cgi.
Прочти как создаются и запускаются модули cgi под Apach, когда он их выгружает. Нужен ли код инициализации.
Приведи код инициализации своего cgi приложения. Покажи как объявлен Socket1 и где он создается.
← →
Alexey (AZ) (2006-11-18 16:15) [19]Автору:
Я так думаю, что надо создать сокет вручную. Т.к. сервис не предполагает наличае чего-либо визуального, то может быть что сокет не создается, в отличае от формы, где после её создания происходит автосоздание компонент, расположеных на ней.
← →
Lesorub © (2006-11-18 16:57) [20]Вот созрел ответ )
CGI-модуль создается в виде исполняемого файла и запускается на выполнение как независимый процесс. В моем случае обычного CGI-интерфейса запрос и сформированный ответ передаются через стандартный консольный ввод/вывод. А выгружает, надо понимать, по завершении работы исполняемого файла. Насколько я читал это верно не только для апача, но и вообще для любых web-серверов которые работают с cgi.
Сокет объявляется так:
type
TWebModule1 = class(TWebModule)
Socket1: TClientSocket; { эта строка появляется автоматически при перетаскивании компонента на webmodule }
То же самое и при перетаскивании на форму в обычных приложениях, только вместо class(TWebModule) конечно же class(TForm).
Alexey (AZ), вот может действительно так и надо сделать, потому как нет уверенности, что при помещении компонента на webmodule, он автоматически создается. Если нет автосоздания то это наверное связано со спецификой webmodule. Хотя, странно, что это может помешать автосозданию.
И, если можно, объясните как создать вручную, в литературе все практически начинается с того что компонент создается автоматически при перетаскивании.
← →
Lesorub © (2006-11-18 17:21) [21]Хм, или надо объявить как переменную типа Socket1 ?
← →
Lesorub © (2006-11-18 20:15) [22]ну и глупость предыдущий сабж :-)
← →
MikePetrichenko © (2006-11-18 21:43) [23]
> Lesorub © (18.11.06 16:57) [20]
Не парься с WebModule. CGI пишется весь ручками. От начал и до конца. Иначе будут головные боли.
← →
Плохиш © (2006-11-18 22:26) [24]
> MikePetrichenko © (18.11.06 21:43) [23]
> Не парься с WebModule. CGI пишется весь ручками. От начал
> и до конца. Иначе будут головные боли.
Не пугай мальчика :-)
> Lesorub © (18.11.06 16:57) [20]
Вот, почитай http://delphi.about.com/od/webservices/
← →
Lesorub © (2006-11-19 09:55) [25]Вот, теперь делаю так:
var
S: TClientSocket;
...
//создаем
S:=TClientSocket.Create(self);
S.Address:="127.0.0.1";
S.Port:=80;
S.Open;
S.Close;
S.Free;
Достижение, обращение клиента проходит нормально. Но зато другая появилась проблема - при открытии сокета свойство Active не переходит в true, даже если явно указать после S.Open строку S.Active:=true.
← →
MikePetrichenko © (2006-11-19 09:59) [26]
> S.Open;
> S.Close;
> S.Free;
Так ты же его сразу закрываешь.
← →
Lesorub © (2006-11-19 10:08) [27]ага, но без этих строчек
S.Close;
S.Free;
все равно то же самое...
после S.Open пишу
if S.Active=true then Conn:="active"
else Conn:="not active";
а потом наблюдаю за переменной Conn - "not active", вот ведь как.
← →
Lesorub © (2006-11-19 10:08) [28]теперь то что ему не хватает
← →
Lesorub © (2006-11-19 10:15) [29]хм, может ему какое-то время надо на открытие
← →
MikePetrichenko © (2006-11-19 11:20) [30]
> хм, может ему какое-то время надо на открытие
Сокет Blocked или Non Blocked?
← →
Lesorub © (2006-11-19 11:23) [31]non blocked, в асинхронном режиме
пишу так:
S.ClientType:=ctNonBlocking;
← →
MikePetrichenko © (2006-11-19 11:28) [32]Тогда он практически НИКОГДА не будет сразу Active = True. Читай про Overlapped IO и Thread blocking sockets.
Думай. И будет тебе просветление.
← →
Lesorub © (2006-11-19 11:30) [33]Ок, надо почитать :-)
← →
Lesorub © (2006-11-19 11:39) [34]Кстати, теперь после S.Open делаю паузу 10 секунд с помощью Application.ProcessMessages и цикла. Неужели 10 секунд не хватает чтобы перейти S.Active в true !
← →
Lesorub © (2006-11-19 11:46) [35]НО! Теперь пишет, после того как поставил паузу, ошибку показывает такую: InternalServerError (500)
← →
Anatoly Podgoretsky © (2006-11-19 13:05) [36]> Lesorub (19.11.2006 11:46:35) [35]
Так у тебя ошибка в сервисе.
← →
Lesorub © (2006-11-19 13:29) [37]ага, но откуда!
← →
Lesorub © (2006-11-19 13:52) [38]Код процедуры "пауза" без ошибок
← →
Lesorub © (2006-11-19 20:22) [39]а может запрещено winsock.dll исользовать в cgi, как думаете?
← →
Anatoly Podgoretsky © (2006-11-19 20:32) [40]> Lesorub (19.11.2006 20:22:39) [39]
Думаем, что нет, поскольку cgi это обычное консольное приложение
← →
Lesorub © (2006-11-19 20:52) [41]хм, но что же тогда, почему же ошибка возникает когда сокету дается время (пауза 10 сек) на открытие
← →
Сергей М. © (2006-11-20 08:10) [42]
> Lesorub © (19.11.06 20:52) [41]
Не надо сокету давать никакую "паузу".
Либо установи ctBlocking, либо органигуй цикл ожидания/выборки/диспетчеризации оконных сообщений.
← →
MikePetrichenko © (2006-11-20 10:03) [43]
> НО! Теперь пишет, после того как поставил паузу, ошибку
> показывает такую: InternalServerError (500)
Правильно пишет.
Вообще это идиотизм, использовать асинхронные сокеты с процедурой задержки, уж простите.
Пользуй либо синхронные, либо события OnConnect OnDisconnet.
P.S. В дельфе асинхронная работа сокетов сделана на основе оконных сообщений (что ни есть гуд для CGI). Следствие. Пиши ручками с использование Event, либо пользуй синхронные, либо события.
← →
Lesorub © (2006-11-25 11:21) [44]Читал много. Размышлял.
В общем, действительно это глупость использовать задержку. Совершенно согласен теперь с тем, что, в случае асинхронных сокетов, надо писать класс с эвентами, чтобы обрабатывать те самые оконные сообщения, либо использовать синхронные. Сначала пробую использовать синхронные. Причем решил не использовать vcl, а использовать api-функции winsock, поскольку в этом случае приложение как-то более контролируемо.
Делаю подготовку так:
if wsastartup($101,vwsadata)<>0 then halt(1);
vsocket := socket(af_inet,sock_stream,ipproto_ip); //создается сокет
if vsocket = invalid_socket then halt(1);
fillchar(vsockaddr,sizeof(tsockaddr),0);
vsockaddr.sin_family := af_inet;
vsockaddr.sin_port := htons(cport);
vsockaddr.sin_addr.s_addr := inet_addr(ip);
if connect(vsocket,vsockaddr,sizeof(tsockaddr)) = socket_error then halt(1);
//затем отсылаем данные
send(vsocket,buf[1],length(buf),0);
//затем надо принять ответ
recv(vsocket,chresp,1,0);
То есть хочу считывать по одному байту, и с этой целью надо поместить recv в цикл. И вот тут как определить сколько данных пришло в сокет?
А так вроде работает. Как думаете, правильно так делать?
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2006.12.10;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.048 c