Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M Новый топик    Ответить
 Аналог сокета GT.M в Cache  [new]
Valeriu
Member

Откуда: Chisinau
Сообщений: 2005
Доброго времени всем.
Помогите писать кусочек кода для работы с сокетом по аналогии GT.M в Каше
(версия старая 5,0), я не очень силен в сокетах Каше
Не пинайте сильно.

Код работающий в GT.M:
+
listen
 n tcpdev,nr,SYSGLD
 s nr=0 
 s timeo=30
 s port=9998
 s ^fcgilog(1,"knownserver")=port_"`"_$j
 s tcpdev="SCK$"_$S
 o tcpdev:(ZLISTEN=port_":TCP":NODELIMITER:ZNODELAY:ATTACH="listener"):timeo:"SOCKET"
 e  s ^fcgilog($job)="-1,NotOpen" q
 u tcpdev
 w /listen(1)
 f  d  q:$key]""
 . w /wait(timeo)
 . i $key]"" q
 s socket=$p($key,"|",2)
 c tcpdev:(SOCKET="listener") j listen^FCGIjobs 
loop 
    n $zt s $zt="goto errstop^FCGIjobs"
    u tcpdev:(NODELIMITER:ZNODELAY:SOCKET=socket)
    r *version,*type,*requestIdB1,*requestIdB0 s requestId=256*requestIdB1+requestIdB0
    r *contentLengthB1,*contentLengthB0,*paddingLength,*reserved
    s contentLength=256*contentLengthB1+contentLengthB0
    s contentData="" i contentLength r contentData#contentLength
    s paddingData="" i paddingLength r paddingData#paddingLength
    i type=1 s nr=nr+1 do  g loop
   .......
   итд


Спасибо.
17 май 18, 16:44    [21417823]     Ответить | Цитировать Сообщить модератору
 Re: Аналог сокета GT.M в Cache  [new]
Valeriu
Member

Откуда: Chisinau
Сообщений: 2005
Я получаю что-то, но очень и очень туманно ...
Может подскажите что я делаю не так ???
Примерно такой код:
+
webFC ;;
 ;
 QUIT
 ;
Version()
 ;; Build2
 q
port
 ;;9998
 ;
server ;
     s nr=0
     SET io="|TCP|1"
     SET ^serverport=9998
     OPEN io:(:^serverport:"ACT"):15 
     IF $TEST=0 {
     WRITE !,"Cannot open server port"
     QUIT }
     ELSE { WRITE !,"Server port opened" }
loop USE io READ x ; Read for accept        
     USE 0 WRITE !,"Accepted connection",!
     JOB child:(:5:io:io) ;Concurrent server bit is on
     ;GOTO loop
     ;QUIT
child
    WRITE $JOB,! ;Send job id on TCP device to be read by client
    ;write *-3
     USE io
    ;u $io:(::"+Q":$c(10))
    ;use $io:(/IOTABLE="UTF8"::"-Q+W":$c(0))
    ;U $P:(::"CT")
    s ^CON(1)="TEST"    
    r *version,*type,*requestIdB1,*requestIdB0 s requestId=256*requestIdB1+requestIdB0
    r *contentLengthB1,*contentLengthB0,*paddingLength,*reserved
    s contentLength=256*contentLengthB1+contentLengthB0
    s contentData="" i contentLength r contentData#contentLength
    s paddingData="" i paddingLength r paddingData#paddingLength
    s ^CON(2)="version -"_version
    s ^CON(3)="type -"_type
    s ^CON(4)="requestIdB1 -"_requestIdB1
    s ^CON(5)="requestIdB0 -"_requestIdB0
    s ^CON(6)="requestId -"_requestId
    i type=1 s nr=nr+1 do  g child
     ;. f i=1:1:contentLength s ^type1(i)=$A(contentData,i)
    i type=4 s %fcgi("i","params")=$G(%fcgi("i","params"))_contentData d:'contentLength  g child
    . s pos=1 f  q:pos>$L(%fcgi("i","params"))  do
    . . s l1=$A(%fcgi("i","params"),pos),l2=$A(%fcgi("i","params"),pos+1)
    . . s %fcgi("i","header",$E(%fcgi("i","params"),pos+2,pos+2+l1-1))=$E(%fcgi("i","params"),pos+2+l1,pos+2+l1+l2-1)
    . . s pos=pos+l1+l2+2
    . k %fcgi("i","params")
    i type=5&(contentLength>0) s %fcgi("i","stdin")=$G(%fcgi("i","stdin"))_contentData g child    
    ; Jetzt sind alle Daten da
    ;
    s %fcgi("o","header","Set-Cookie")="SID="_$S($G(%fcgi("i","header","SID"))="":($P($H,",")_"00000"+$P($H,",",2))_nr_",1",1:$P(%fcgi("i","header","SID"),",")_","_($P(%fcgi("i","header","SID"),",",2)+1))
    s ^CONN(1)="TEST1"
    i $G(%fcgi("i","header","HTTP_CONTENT_TYPE"))="application/x-www-form-urlencoded" d HTMLVARDECODE(%fcgi("i","stdin"),"%fcgi(""i"",""_POST""")
    i %fcgi("i","header","QUERY_STRING")'="" d HTMLVARDECODE(%fcgi("i","header","QUERY_STRING"),"%fcgi(""i"",""_GET""")
    ; Jetzt auf Programme verteilen
    s t=$G(^%FCGI("DOCUMENT_URI",$P(%fcgi("i","header","DOCUMENT_URI"),"/",1,3)))
    s sid=$p(%fcgi("i","header","SID"),",")
    i sid="" s sid=$j ; ???
    s ^CONN(2)="TEST2"
    d:t'="" startappl(t)
    s (ind,txt)="" f  s ind=$O(%fcgi("o","header",ind)) q:ind=""  s txt=txt_ind_": "_%fcgi("o","header",ind)_$C(13,10)
    s txt=txt_$C(13,10)
    ;u tcpdev:(NODELIMITER:ZNODELAY:SOCKET=socket) ; why   ???
    u $io:(::"+Q":$c(10))
    w $C(1,6,requestIdB1,requestIdB0,$L(txt)\256,$L(txt)#256,0,0),txt
    i $G(%fcgi("o","stdout"))'="" w $C(1,6,requestIdB1,requestIdB0,$L(%fcgi("o","stdout"))\256,$L(%fcgi("o","stdout"))#256,0,0),%fcgi("o","stdout")
    w $C(1,6,requestIdB1,requestIdB0,0,0,0,0) ; stdout Complete
    w $C(1,3,requestIdB1,requestIdB0,0,8,0,0),$C(0,0,0,0,0,0,0,0) ; Request Complete
    c $io:(::"+Q":$c(10))
    g loop
    q
    ;
startappl(appl)
 s sid=$p(%fcgi("i","header","SID"),",",1) ;i sid="" s sid=$job
 d @appl
 q
 ;
record(type,data)   ; Not used
    w $C(1,type,requestIdB1,requestIdB0,$L(data)\256,$L(data)#256,0,0)_data
    q
    ;
init ;  Not used
    n (fcgi)
    s fcgi("type",1,"FCGI_BEGIN_REQUEST")=1
    s fcgi("type",1,"FCGI_ABORT_REQUEST")=2
    s fcgi("type",1,"FCGI_END_REQUEST")=3
    s fcgi("type",1,"FCGI_PARAMS")=4
    s fcgi("type",1,"FCGI_STDIN")=5
    s fcgi("type",1,"FCGI_STDOUT")=6
    s fcgi("type",1,"FCGI_STDERR")=7
    s fcgi("type",1,"FCGI_DATA")=8
    s fcgi("type",1,"FCGI_GET_VALUES")=9
    s fcgi("type",1,"FCGI_GET_VALUES_RESULT")=10
    s fcgi("type",1,"FCGI_UNKNOWN_TYPE")=0
    ;
HTTPSTATUS401(realm)
    s %fcgi("o","header","Status")="401 Unauthorized"
    s %fcgi("o","header","WWW-Authenticate")="Basic realm="""_realm_""""
    s %fcgi("o","header","Content-Type")="text/plain",%fcgi("o","stdout")="Unauthorized"
    q
    ;
HTMLVARDECODE(data,var)  ; Decodiert nach HTML-Variablen-Standard
    ;w data,!,var,!
    n l,i,ind,val,t
    s l=$L(data,"&") f i=1:1:l s t=$P(data,"&",i) d
    . ;s ind=$$CONVERT($TR($P(t,"="),lower,upper)),val=$$CONVERT($P(t,"=",2))
    . s ind=$$CONVERT($P(t,"=")),val=$$CONVERT($P(t,"=",2))
    . i $L(ind) s @(var_","""_ind_""")")=val ;w ind,": ",val,!
    q
    ;
HEX2DEZ(dez)	;
    n (dez) s hex=0,dez=$TR(dez,"abcdef","ABCDEF")
    f i=1:1:$L(dez) s hex=hex*16+$s($A(dez,i)>59:$A(dez,i)-55,1:$E(dez,i))
    q hex
    ;
CONVERT(t)	;
    n (t)
    s t=$TR(t,"+"," "),p=0
    f  s p=$F(t,"%",p) q:p<1  s t=$E(t,1,p-2)_$C($$HEX2DEZ($E(t,p,p+1)))_$E(t,p+2,255)
    q t
    ;

При инициирование ВЕБ страницы в терминале получаю;
+
USER>d server^%FCGI

Server port opened
Accepted connection
6553

    i %fcgi("i","header","QUERY_STRING")'="" d HTMLVARDECODE(%fcgi("i","header",
    ^
"QUERY_STRING"),"%fcgi(""i"",""_GET""")
<UNDEFINED>child+32^%FCGI
USER 2d0>zw

%fcgi("o","header","Set-Cookie")="SID=64786562601,1"
contentData="ID"
contentLength=18179
contentLengthB0=3
contentLengthB1=71
io="|TCP|1"
nr=1
paddingData=""
paddingLength=0
requestId=18766
requestIdB0=78
requestIdB1=73
reserved=83
type=82
version=84
x=""
 
18 май 18, 15:53    [21420761]     Ответить | Цитировать Сообщить модератору
 Re: Аналог сокета GT.M в Cache  [new]
Alexey Maslov
Member

Откуда: СПб
Сообщений: 1520
Зачем закомментирован GOTO loop ? Было правильно. Структура сокет-сервера:

слушаем
if словили коннект, job child, передав ему код 5 = открытый сокет (4) + таблицу символов (1)
снова слушаем...

Кстати, в последних версиях GT.M (начиная с 6.2 вроде) реализуема и рекомендуется та же структура сокет-сервера, что и в Cache. Отпочковывать job-ом слушатель нехорошо, т.к. какое-то время порт при этом не слушается. Была об этом статейка у Fidelity.
19 май 18, 00:00    [21421801]     Ответить | Цитировать Сообщить модератору
 Re: Аналог сокета GT.M в Cache  [new]
Valeriu
Member

Откуда: Chisinau
Сообщений: 2005
Alexey Maslov,
Можете обьяснить, что имеется введу под "открытый сокет (4) + таблицу символов (1)" ?
Типа этого ?
    ;u $io:(::"+Q":$c(10))
    u $p:(/IOTABLE="UTF8"::"PSTE")
    ;u $p:(/IOTABLE="RAW"::"-Q+W"::32000)
    ;U $P:(::"PSTE")


Видно, что-то не правильно получает сокет со стороны nginx здесь:

i %fcgi("i","header","QUERY_STRING")'="" d HTMLVARDECODE(%fcgi("i","header","QUERY_STRING"),"%fcgi(""i"",""_GET""")
21 май 18, 14:57    [21426112]     Ответить | Цитировать Сообщить модератору
 Re: Аналог сокета GT.M в Cache  [new]
Alexey Maslov
Member

Откуда: СПб
Сообщений: 1520
Открытый сокет - сокет с открытым tcp-соединением. Код 4 в команде JOB. Кода 16 в 5.0 вроде бы ещё не было.
Таблица символов - все локальные переменные процесса. Код 1 в JOB. (Передавать не обязательно).
Всё по примеру: http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GIOD_tcp#GIOD_tcp_connect_job
В Cache 5.0 наверняка были отличия, которых я уже не помню, но и аналогичный пример тоже был, более-менее рабочий, ЕМНИП.

Лучше отладить сокет-сервер на простейших примерах, (чтобы и клиент был на COS/mumps), научиться уверенно ловить соединение, потом уже переходить к нюансам nginx.
21 май 18, 17:35    [21426743]     Ответить | Цитировать Сообщить модератору
 Re: Аналог сокета GT.M в Cache  [new]
Valeriu
Member

Откуда: Chisinau
Сообщений: 2005
Alexey Maslov,

<<Лучше отладить сокет-сервер на простейших примерах, (чтобы и клиент был на COS/mumps), научиться уверенно ловить соединение, потом уже переходить к нюансам nginx.>>

Этот сокет давно я раскусил на примерах MWire Rob Twid-а ...
Работает безупречно ...
+
port
 ;;9998
 ;
start
 i $zv["GT.M" QUIT
 n io,port,x
 ;
 l +^zmwire("daemon"):0 e  QUIT  ; already running
 ;
 s io="|TCP|1" 
 s port=$p($t(port+1),";;",2) 
 o io:(:port:"PTA"):20 e  QUIT
 u io
loop
 r x
 j child:(:5:io:io)
 g loop
 ;
child
 ;
 u $io:(::"+Q":$c(10))
 d command^zmwire
 QUIT
 ;

Вот вклинить его для общения с nginx никак не могу..
+
server {
	listen 8082 default_server;
	listen [::]:8082 default_server ipv6only=on;

	root /media/sf_share/html/;
	index index.html index.htm;
	server_name localhost;

        location ~ (\.m$|^/cache/.*) {
              fastcgi_pass 127.0.0.1:9998;
		fastcgi_param   QUERY_STRING            $query_string;
		fastcgi_param 	SID 			$cookie_sid;
		fastcgi_param   DOCUMENT_URI            $document_uri;
		fastcgi_param   REQUEST_METHOD          $request_method;
        }
}
22 май 18, 18:52    [21430259]     Ответить | Цитировать Сообщить модератору
 Re: Аналог сокета GT.M в Cache  [new]
Alexey Maslov
Member

Откуда: СПб
Сообщений: 1520
Valeriu,

Возможно, причина в том, что fastcgi - это двоичный протокол, а в примерах (включая MWire) чаще встречается текстовый. Пишу сейчас в фоновом режиме двоичный сокет-сервер. Гашу разделители (/TER="") и делаю всё сам. Мне проще, т.к. протокол мой собственный. Вам придётся подстраиваться под "чужое": скорее всего читать length#N, распаковывать длину, потом читать message#lengthUnpacked.
23 май 18, 11:45    [21431655]     Ответить | Цитировать Сообщить модератору
 Re: Аналог сокета GT.M в Cache  [new]
Valeriu
Member

Откуда: Chisinau
Сообщений: 2005
Alexey Maslov,
Вроде вклинил ...
Заработал. Все с ВЕБ страницы получаю в каше, сформировал даже
при вызове рутины - глобаль ^mTEMP. Осталось из него $order-м выбирать
и обратно отсылать на ВЕБ страницу и заполнить таблицу.
Если получится и обратно, я "победил"
23 май 18, 12:28    [21431867]     Ответить | Цитировать Сообщить модератору
 Re: Аналог сокета GT.M в Cache  [new]
Alexey Maslov
Member

Откуда: СПб
Сообщений: 1520
Valeriu,

рад слышать.
глобаль ^mTEMP
Лучше ^mtempУникальныйСуффикс, тогда попадёт в нежурналируемую БД CACHETEMP, которая к тому же чистится при [ре]старте Cache.
23 май 18, 13:05    [21432058]     Ответить | Цитировать Сообщить модератору
 Re: Аналог сокета GT.M в Cache  [new]
Valeriu
Member

Откуда: Chisinau
Сообщений: 2005
Alexey Maslov,
<<Лучше ^mtempУникальныйСуффикс,>>

Думаю SID ему присвоить.
Примерно так работает сокет:
+
webFC ;;Compilation 
 ;
 QUIT
 ;
Version()
 ;; Build2
 q
port
 ;;9998
 ;
start
 s nr=0
 s ^serverport=9998
 s tcpport=^serverport
server ;
     k (io,tcpport,nr,DDB)
     s io="|TCP|"_tcpport
     o io:(:tcpport:"AS"):5
     i $t=0 {
     u 0 w !,"Cannot open server port"
     q }
     else { u 0 w !,"Server port opened" }
loop u io r x ; Read for accept        
     u 0 w !,"Accepted connection",!
     j ini(io,tcpport,nr):(:5:io:io):5
     I $ZA\8196#2=1 w *-2 ;job failed to clear bit
     g loop
     q
ini(io,tcpport,nr)
    ;     
child
    n $es n $et s $et="g:'$es error"
    s io=$i
    u io
    r *version,*type,*requestIdB1,*requestIdB0 s requestId=256*requestIdB1+requestIdB0
    r *contentLengthB1,*contentLengthB0,*paddingLength,*reserved
    s contentLength=256*contentLengthB1+contentLengthB0
    s contentData="" i contentLength r contentData#contentLength
    s paddingData="" i paddingLength r paddingData#paddingLength
    i type=1 s nr=nr+1 do  g child
     . f i=1:1:contentLength s ^type1(i)=$A(contentData,i)
     . w !
    i type=4 s %fcgi("i","params")=$G(%fcgi("i","params"))_contentData d:'contentLength  g child
    . s pos=1 f  q:pos>$L(%fcgi("i","params"))  do
    . . s l1=$A(%fcgi("i","params"),pos),l2=$A(%fcgi("i","params"),pos+1)
    . . s %fcgi("i","header",$E(%fcgi("i","params"),pos+2,pos+2+l1-1))=$E(%fcgi("i","params"),pos+2+l1,pos+2+l1+l2-1)
    . . s pos=pos+l1+l2+2
    . k %fcgi("i","params")
    i type=5&(contentLength>0) s %fcgi("i","stdin")=$G(%fcgi("i","stdin"))_contentData g child    
    ; Jetzt sind alle Daten da
    ;
    s %fcgi("o","header","Set-Cookie")="SID="_$S($G(%fcgi("i","header","SID"))="":($P($H,",")_"00000"+$P($H,",",2))_nr_",1",1:$P(%fcgi("i","header","SID"),",")_","_($P(%fcgi("i","header","SID"),",",2)+1))
    i $G(%fcgi("i","header","HTTP_CONTENT_TYPE"))="application/x-www-form-urlencoded" d HTMLVARDECODE(%fcgi("i","stdin"),"%fcgi(""i"",""_POST""")
    i %fcgi("i","header","QUERY_STRING")'="" d HTMLVARDECODE(%fcgi("i","header","QUERY_STRING"),"%fcgi(""i"",""_GET""")
   .....
   ....
    c io
    g loop
    q

Получилось, заполнил таблицу.
Огорчает одно, всегда нужно смотреть на длину строки,
передавая клиенту порциями, иначе получаю ошибку "максимальная строка"
23 май 18, 13:52    [21432314]     Ответить | Цитировать Сообщить модератору
Все форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M Ответить