III. Communications Server REXX

Автор: Kádár Zsolt

Дата: 09.05.1999

Источник: https://xenia.sote.hu

Язык: Венгерский

Fôképpen nagyvállalatok vagy bankok által üzemeltetett SNA (Systems Network Architecture) hálózatában használatos az APPC (Advanced Program-to-Program Communications) protokoll. OS/2 alatt a Communications Manager, illetve a már a 2000. év problémáját is megoldó utódja, a Communications Server teszi lehetôvé az APPC használatát. A Communications Server (vagy Manager) szolgáltatásainak nagy részét REXX-bôl is el lehet érni a megfelelô beépített vagy utólag telepített bôvítômodulok használatával.

APPC alapismeretek

Ismerkedjünk meg elôször a példaprogramok megértéséhez minimálisan szükséges APPC alapfogalmakkal! Az APPC protokoll segítségével kommunikálhatnak egymással a fizikailag többnyire különbözô gépeken elhelyezkedô (rész)programok, amelyeket tranzakciós programoknak (TP) neveznek. A tranzakciós programok gyakorlatilag az SNA hálózat bármelyik csomópontjában (node) elôfordulhatnak, s a kommunikáció szempontjából egyenrangú partnernek számítanak (peer network). Az együttmûködô programokat egyetlen nagy alkalmazásnak is lehet tekinteni. A tranzakciós programot 64 bájt hosszú neve azonosítja (tp_name), s két különbözô fajtája lehet: APPC tranzakciós program vagy CPI kommunikációs tranzakciós program (CPI = Common Programming Interface). Mint már említettük, az APPC tranzakciós program általában nem egy különálló alkalmazás, hanem egy elosztott alkalmazás része. Egy alkalmazás tehát több APPC tranzakciós programot is tartalmazhat, amelyeket egy 8 bájt hosszú szám azonosít (tp_id). Az APPC technológia vezérlôparancsokat alkalmaz, amelyekkel el lehet indítani és meg lehet állítani az alkalmazás részét képezô tranzakciós programokat. A vezérlôparancsok mellett rendelkezésre állnak még az adatcsere parancsok is, amelyekkel a tranzakciós program által végrehajtandó feladat írható le. A CPI kommunikációs tranzakciós programok ugyancsak az APPC szolgáltatásait használják, azonban a vezérlôparancsok helyett CPI kommunikációs függvényhívásokkal dolgoznak. Minden tranzakciós program az úgynevezett logikai egységeken (LU = Logical Unit) keresztül használja a hálózatot. A LU nem más, mint egy SNA hálózati komponens, amely reagál a tranzakciós programok által küldött vezérlô vagy adatcsere parancsokra. A logikai egységeknek több fajtája is lehet. Az APPC protokoll a LU 6.2-t használja, ezért a többiekrôl itt nem is teszünk említést. Minden, a kommunikációban résztvevô gép Communications Managerének konfigurációjában meg kell adni a saját és a partner programok LU-ját. Erre azért van szükség, hogy a tranzakciós programok a kommunikáció megkezdése elôtt kapcsolatba (session) léphessenek egymással. Ezt a kapcsolatot nevezik LU-LU kapcsolatnak. Amennyiben a kapcsolat felépült, akkor a tranzakciós programok megkezdhetik az adatcserét (conversation). Az adatcsere akkor indul meg, amikor az egyik tranzakciós program kiadja azt a vezérlôparancsot (vagy CPI kommunikációs parancsot), amely az adatcsere kezdetét jelzi. Egyúttal megadja az adatcsere módját is, amely fél duplex, vagy pedig duplex lehet. Egy kapcsolaton keresztül több szekvenciális adatcsere is folyhat. A tranzakciós programok párhuzamos kapcsolatot is kiépíthetnek, s ekkor egy idôben több adatcsere is folyhat. Az adatcserének két fô típusa van. Az elsô típus a basic (alap), amely alacsonyszintû adatcserét jelent. Ebben az esetben a küldô tranzakciós program saját maga puffert épít az adatcsere alapegységét képezô logikai rekordokból, amelyet aztán egy lépésben küld el. A fogadó tranzakciós programnak természetesen fel kell tudni dolgoznia a puffert. LL típusú vétel esetén az APPC alrendszer gondoskodik a puffer logikai rekordokra bontásáról, ami nagyon megkönnyíti a feldolgozást. Puffer típusú vétel esetén a szétbontást a fogadó program végzi, ezért erre külön fel kell készíteni. Mindkét típusú vétel esetén a logikai rekordok felépítésének meg kell felelni bizonyos szabályoknak. Az elsô két bájtnak például tartalmaznia kell a rekord hosszát 370-es adatformátumban (high-order byte formátum). A másik típusú adatcsere a mapped adatcsere. Ebben az esetben komplett adatblokkok küldése folyik, amelybe az APPC alrendszer nem avatkozik bele. Ebbôl adódóan az adatblokkok formátumára nézve nincs különösebb megkötés (és nincsenek logikai rekordok sem).

APPC tranzakciós programok REXX-ben

A DEVCON 8-as CD-n találtam meg a Sam Detweiler által kifejlesztett RXAPPC bôvítômodult, amellyel (valószínûleg elsôként) lehetôség nyílt a Communications Manager APPC API-k REXX programokból történô használatára. A kiegészítô modul telepítése a már megszokott módon azzal kezdôdik, hogy be kell másolni a zip fájlban fellelhetô SAAAPPC.DLL fájlt egy olyan könyvtárba, amely a LIBPATH-ban található. Amennyiben a késôbbiekben bemutatott példaprogramokat is ki akarjuk próbálni, akkor ki kell bôvíteni a Communications Manager/Server aktív konfigurációját leíró NDF fájlt (amely Communications Server esetén a CMLIB alkönyvtárban található) az alábbi részlettel:

DEFINE_TP  TP_NAME(LECKE03B)
	FILESPEC(idrive\os2\cmd.exe)
	PARM_STRING(/c [fdrive\fpath\]LECKE03B.CMD)
	CONVERSATION_TYPE(EITHER)
	CONV_SECURITY_RQD(NO)
	SYNC_LEVEL(EITHER)
	TP_OPERATION(NONQUEUED_AM_STARTED)
	PROGRAM_TYPE(VIO_WINDOWABLE)
	RECEIVE_ALLOCATE_TIMEOUT(INFINITE);

Az idrive helyére azt a meghajtót kell beírni, ahová az OS/2 lett telepítve. Az fdrive\fpath pedig arra a könyvtárra mutasson, ahol a LECKE03B.CMD található, már amennyiben az egy olyan könyvtár, amelyik nincs benne a PATH-ban. Ezek után frissíteni kell a Communications Server konfigurációját a CMVERIFY confignév /E paranccsal. A confignév változó helyébe a fenti módon kibôvített NDM fájl nevét kell beírni. A bôvítôfüggvényeket (amely formailag egyetlen APPC nevû függvény) az alábbi paranccsal lehet a REXX programokban regisztrálni és ezáltal használni:

Call RxFuncAdd 'APPC', 'SAAAPPC', 'APPCSRV'

A kiegészítô függvények két csoportba sorolhatók. Az elsô csoportba az APPC vezérlôparancsok, a másodikba pedig az adatcsere parancsokat leíró függvények tartoznak. Formailag egyetlen függvényt (APPC) tartalmaz az RXAPPC kiegészítô könyvtár. A függvény elsô paramétere határozza meg, hogy tulajdonképpen melyik függvényrôl van szó:

APPC( függvény, [függvényspecifikus adat])

Az alábbi két táblázatban összefoglaltuk a vezérlô és az adatcsere parancsokat leíró függvényeket.

Vezérlôparancsok:

Funkció és szintakszis: Paraméterek: Visszatérési érték:
Kapcsolatra várás: APPC('Receive_allocate', tpnév, összetett_változó) tpnév = a várakozó program neve (EBCDIC érték hexában), az összetett változóban a következô információt találjuk: .0 = tp_ID, .1 = adatcsere_ID, .2 = szinkronizációs szint ('N' = None, 'C' = Confirm), .3 = adatcsere típusa ('B' = alap/basic, 'M' = mapped), .4 = user_ID, .5 = LU alias, .6 = partner LU, .7 = módnév 0 = OK, vagy megfelelô hibakód
Tranzakciós program indítása: APPC('Tp_started', [LU alias], tpnév, összetett változó) LU alias = a kapcsolatra váráskor megadott érték, tpnév = az indított program neve (EBCDIC érték hexában), az összetett változóban a következô információt találjuk: .0 = tp_ID 0 = OK, vagy megfelelô hibakód
Tranzakciós program leállítása: APPC('Tp_ended', tp_ID [, típus]) tp_ID = a leállítandó program ID-ja, típus = 'S' (Soft, a kapcsolatot nem szünteti meg) vagy 'H' (Hard, a kapcsolatot is felszámolja) 0 = OK, vagy megfelelô hibakód

Adatcsere parancsok:

Funkció és szintakszis: Paraméterek: Visszatérési érték:
Adatcsere megindítása: APPC('Allocate', tp_ID, partner_LU, módnév, tpnév, típus, visszatérés_kontroll, szinkron_szint, biztonság, összetett_változó) tp_ID = az adatcserét indító program ID-ja, partner_LU = a partner program LU-ja, módnév = az adatcserét indító program módja, tpnév = az adatcserét indító program neve (EBCDIC érték hexában), típus = 'B' (Basic) vagy 'M' (Mapped), visszatérés_kontroll = 'A' (Allocated, a függvény akkor tér vissza, ha az adatcsere létrejött), 'I' (Immediate, a függvény azonnal visszatér), 'F' (Free, a függvény akkor tér vissza, ha az adatcsere lehetséges), szinkron_szint = 'N' (None, a kapcsolat alatt nem lehet szinkronizációs parancsokat használni), 'C' (Confirm, a kapcsolat alatt lehet szinkronizációs parancsokat használni), biztonság = 'None' (nincs a biztonsági mechanizmus bekapcsolva), 'Same' (a user ID ellenôrzése a lokális tp indításakor hajtódik végre), 'Pgm User Password' (a partner LU ellenôrzi a megadott User/Password kombinációt), összetett változó = további információt tárol, ha az adatcsere indítása sikeres (.1 = az adatcsere ID-ja, .2 = elsôdleges visszatérési kód, .3 = másodlagos visszatérési kód, .4 = adat). 0 = OK, vagy megfelelô hibakód
Kéri a partner programtól a legutolsó tranzakció visszaigazolását. A függvény hatására a pufferben lévô adatok elküldésre kerülnek és a program várakozik a partner válaszára. Csak akkor használható, ha az adatcsere szinkron-szintje 'Confirm': APPC('Confirm', tp_ID, konv_ID, típus) tp_ID = tp azonosítója, konv_ID = az adatcsere azonosítója, típus = 'B' (Basic/alap), 'M' (Mapped) 0 = OK, vagy megfelelô hibakód
Visszaigazolja legutolsó tranzakciót. Csak akkor használható, ha az adatcsere során 'Confirm' kérés érkezik: APPC('Confirmed', tp_ID, konv_ID, típus) tp_ID = tp azonosítója, konv_ID = az adatcsere azonosítója, típus = 'B' (Basic/alap), 'M' (Mapped) 0 = OK, vagy megfelelô hibakód
Adatformátum átalakítása: APPC('Convert', irány, tábla, kifejezés) irány = a konvertálás iránya, lehetséges értékek: 'A' (EBCDIC -> ASCII), 'E' (ASCII -> EBCDIC), tábla = 'A' (a CM A transzlációs tábláját használja a konverzióhoz), 'E' (a CM AE transzlációs tábláját használja a konverzióhoz), 'G' (a CM G transzlációs tábláját (felhasználó által megadott) használja a konverzióhoz), kifejezés = az átalakítandó adat Az átalakított adat, vagy üres karakterlánc hiba esetén.
Adatcsere befejezése: APPC('Deallocate', tp_ID, konv_ID, típus, dtípus) tp_ID = tranzakciós program ID, konv_ID = a befejezendô adatcsere ID-ja, típus = 'B' (Basic), 'M' (Mapped), dtípus = 'F' (Flush, normális befejezés), 'A' (Abend, abnormális befejezés) 0 = OK, vagy megfelelô hibakód
A pufferben található adatok elküldése a partner LU-nak: APPC('Flush', tp_ID, konv_ID, típus) tp_ID = tranzakciós program ID, konv_ID = az adatcsere ID-ja, típus = 'B' (Basic), 'M' (Mapped) 0 = OK, vagy megfelelô hibakód
Megadja a kívánt adatcsere attribútumait: APPC('Get_attributes', tp_ID, konv_ID, típus, összetett_változó) tp_ID = tranzakciós program ID, konv_ID = a befejezendô adatcsere ID-ja, típus = 'B' (Basic), 'M' (Mapped), összetett_változó = ebben kerül eltárolásra a függvény által visszaadott információ, .0 = a hálózat neve (net name), .1 = LU név, .2 = LU alias, .3 = a partner LU lokális neve, .4 = a partner LU hálózaton ismert neve, .5 = a partner LU teljes neve, .6 = az adatcsere módjának neve, .7 = az adatcsere szinkronizációs módja (N/C), .8 = az adatcseréhez tartozó user ID 0 = OK, vagy megfelelô hibakód
Átváltás küldésbôl fogadásba: APPC('Prepare_to_receive', tp_ID, konv_ID, típus, rtípus, visszatérés) tp_ID = tranzakciós program ID, konv_ID = az adatcsere ID-ja, típus = 'B' (Basic), 'M' (Mapped), rtípus = 'F' (Flush, elküldi a pufferben lévô adatokat), visszatérés = 'S' (Short, a visszaigazolás végrehajtása után azonnal visszatér a függvény), 'L' (Long, a függvény akkor tér vissza, ha adatot kapott a partnertôl) 0 = OK, vagy megfelelô hibakód
Adat fogadása: APPC('Receive_wait', tp_ID, konv_ID, típus, összetett_változó, maxhossz) tp_ID = tranzakciós program ID, konv_ID = az adatcsere ID-ja, típus = 'B' (Basic buffer receive módban), 'L' (Basic logical record receive módban), 'M' (Mapped), összetett_változó = a fogadott adat, .0 = az adat típusa (Data/Data_complete/Data_incomplete), .1 = indikátor, amely jelzi, ha a partner az adatforgalom irányának megváltoztatását kéri, .2 = a fogadott adat, maxhossz = maximális adathossz 0 = OK, vagy megfelelô hibakód
Adat fogadása: APPC('Receive_immediate', tp_ID, konv_ID, típus, összetett_változó, maxhossz) tp_ID = tranzakciós program ID, konv_ID = az adatcsere ID-ja, típus = 'B' (Basic buffer receive módban), 'L' (Basic logical record receive módban), 'M' (Mapped), összetett_változó = a fogadott adat, .0 = az adat típusa (Data/Data_complete/Data_incomplete), .1 = indikátor, amely jelzi, ha a partner az adatforgalom irányának megváltoztatását kéri, .2 = a fogadott adat, maxhossz = maximális adathossz 0 = OK, vagy megfelelô hibakód
Engedély kérése adat küldésére: APPC('Request_to_send', tp_ID, konv_ID, típus) tp_ID = tranzakciós program ID, konv_ID = a befejezendô adatcsere ID-ja, típus = 'B' (Basic), 'M' (Mapped) 0 = OK, vagy megfelelô hibakód
Adatot cserél a partner LU-tal, majd visszaigazolás nélkül felfüggeszti az adatcserét: APPC('Send_Conversation', tp_ID, Partner_LU, módnév, tpnév, típus, visszatérés, biztonság, adat, [konv_csop_ID], összetett_változó) tp_ID = tranzakciós program ID, Partner_LU = partner LU neve, módnév = az adatcserét indító program módjának neve, tpnév = a partner program neve (EBCDIC), típus = 'B' (Basic), 'M' (Mapped), visszatérés = 'A' (Allocated, a függvény visszatér, ha az adatcsere létrejött), 'I' (Immediate, azonnali visszatérés), 'F' (Free, a függvény visszatér, ha az adatcsere lehetséges), 'C' (ConWinner, a függvény visszatér, ha az elsô contention-winner szekció létrejött), 'G' (Group, speciális szekciót hoz létre a konv_csop_ID alatt), biztonság = 'None' (nincs a biztonsági mechanizmus bekapcsolva), 'Same' (a user ID ellenôrzése a lokális tp indításakor hajtódik végre), 'Pgm User Password' (a partner LU ellenôrzi a megadott User/Password kombinációt), összetett_változó = sikeres adatcsere esetén további információt tartalmaz, .1 = konv_csop_ID, ha a visszatérés nem Group, .2 = elsôdleges visszatérési kód, .3 = másodlagos visszatérési kód, .4 = adat 0 = OK, vagy megfelelô hibakód
Adat küldése a partner programnak: APPC('Send_data', tp_ID, konv_ID, típus, adat) tp_ID = tranzakciós program ID, konv_ID = az adatcsere ID-ja, típus = 'B' (Basic), 'M' (Mapped), adat = küldendô adat 0 = OK, vagy megfelelô hibakód
Hibaüzenet küldése: APPC('Send_error', tp_ID, konv_ID, típus, réteg) tp_ID = tranzakciós program ID, konv_ID = az adatcsere ID-ja, típus = 'B' (Basic), 'M' (Mapped), réteg = 'P' (Program, az alkalmazás réteg érzékelte a hibát), 'S' (Service, a LU szervizréteg érzékelte a hibát) 0 = OK, vagy megfelelô hibakód
Ellenôrzi, hogy a partner LU akar-e adatot küldeni: APPC('Test_rts', tp_ID, konv_ID, típus) tp_ID = tranzakciós program ID, konv_ID = az adatcsere ID-ja, típus = 'B' (Basic), 'M' (Mapped) 0 = OK, vagy megfelelô hibakód
Transzlációs táblázat váltása: APPC('Trans_table', táblatípus) táblatípus = 'A' (a CM A transzlációs tábláját használja a konverzióhoz), 'E' (a CM AE transzlációs tábláját (default) használja a konverzióhoz), 'G' (a CM G transzlációs tábláját (felhasználó által megadott) használja a konverzióhoz) 0 = OK

Az RXAPPC csomagban található INF fájlban további angol nyelvû információt lehet találni ezekrôl a függvényekrôl. Ugyanebben a fájlban található meg az a táblázat is, amely kimerítô információt nyújt a függvények hiba esetén visszatérített értékeirôl. Ne feledkezzünk meg arról, hogy a nem nulla visszatérési értékeket át kell alakítani hexadecimális formára a C2X függvénnyel, mielôtt értelmezni tudnánk ôket!

Példaprogramok

A NetBios protokoll programozása közben bemutatott példaprogramokhoz hasonló programokat az APPC protokoll segítségével is meg lehet valósítani. Elsô példaként tekintsük meg azt a programot (kliens), amely üzenetet küld egy másik programnak (szerver), majd pedig fogadja annak válaszát:

/* REXX/APPC tranzakciós program üzenet fogadására (kliens) */

/* Az APPC kiegészítô függvények regisztrálása */
CALL RXFUNCADD APPC, SAAAPPC, APPCSRV

/* A tranzakciós program indítása */
Rc = APPC('Tp_started', ,'lecke03a', 'Lu1s.')

/* Sikerült */
if Rc = 0 then 
	do
	  	tpid = Lu1s.0  /* elmentjük a program ID-t */
	
		/* Bekérjük a partner program LU-ját */
		Say 'Adja meg a Partner LU nevét!'
  		Pull plu .

		/* Létrehozzuk a kapcsolatot a partner programmal */
		Rc = APPC('Allocate', Lu1s.0, plu, '#BATCH', 'LECKE03B', 'MAPPED', 'A', 'N', 'N', 'Lu1P.')

		/* Ha sikerült, akkor ... */
		if Rc = 0 then 
			do
				/* elmentjük az adatcsere ID-t */
				convid = Lu1P.1 

			    	/* üzenünk a partnernek */
			    	Rc = APPC('Send_data', tpid, convid, 'Mapped', 'Hello! Itt a lecke03a!')

				/* most pedig várjuk a partner válaszát */
	   	 		Rc = APPC('Receive_wait', tpid, convid, 'Mapped', 'data.', 1000)

				/* kiírjuk a kapott adatot */
    				Say data.2

  			end
  		else 
			Say 'Nem sikerült a kapcsolat Rc = 'c2x(Lu1P.2),
			    'másodlagos Rc = 'c2x(Lu1P.3) 'Sense kód ='c2x(Lu1p.4)

		/* Kész vagyunk, ezért leállítjuk a tp-t */
	  	Rc = APPC('Tp_ended', tpid)
	end
else 		/* Hiba történt */
	do
  		Say 'A Communications Manager nem fut, vagy pedig'
  		Say 'nincs konfigurálva APPC-re!'
	end

exit

A fenti példaprogram a kiegészítô függvények regisztrálásával kezd, majd pedig indítja a kliens oldali programot. A felhasználónak be kell gépelnie a partner program (szerver) LU-jának nevét (amely a fentebb említett NDF fájl DEFINE_LOCAL_CP FQ_CP_NAME vagy CP_ALIAS mezejében található), amelynek birtokában felvesszük a kapcsolatot. Ha sikerült a kapcsolatfelvétel, vagyis elindult a szerver oldalon a partner tranzakciós program, akkor elküldjük az üdvözölô üzenetünket, és várjuk a választ. Amikor a válasz megérkezik, akkor kiíratjuk azt a képernyôre.

A második példaprogram a szerver oldali tranzakciós program egy lehetséges megvalósítását mutatja be:

/* REXX/APPC tranzakciós program üzenet küldésére (szerver) */

/* Az APPC kiegészítô függvények regisztrálása */
CALL RXFUNCADD APPC, SAAAPPC, APPCSRV

/* Várjuk a kliens jelentkezését */
Rc = APPC('Receive_allocate', 'LECKE03B', 'Lu2s.')

/* Elmentjük a tp és az adatcsere ID-ját */
tpid 	 = Lu2s.0
convid 	 = Lu2s.1

/* Elmentjük az adatcsere típusát (Basic/Mapped) */
ConvType = Lu2s.3

/* Várjuk a kliens üdvözletét */
Rc = APPC('Receive_wait', tpid, convid, ConvType, 'data.', 1000)

/* Kiírjuk az üdvözletet */
Say 
Say 'A kliens szövege: 'data.2

/* Mivel tudjuk, hogy a kliens nem küld több adatot, ezért 	*/
/* rögtön átállunk küldésre. A valós életben ellenôriznünk 	*/
/* kellene, hogy minden adatot megkaptunk-e.			*/
Rc = APPC('Receive_immediate', tpid, convid, ConvType, 'data1.', 1000)

/* Küldjük az adatot */
Rc = APPC('Send_data', tpid, convid, ConvType, 'Hello! Itt a lecke03b!')

/* Készen vagyunk. */
Rc = APPC('Tp_ended', tpid)

exit

A szerver program ugyancsak a kiegészítô APPC függvény regisztrálásával indít, s az után rögtön vételi üzemmódba áll. Amint érzékeli, hogy a kliens kapcsolatot keres, elmenti az adatcseréhez szükséges paramétereket és fogadja, majd pedig kiírja a kliens üdvözletét. Mivel tudjuk, hogy a kliens nem küld több üzenetet, ezért rögtön küldésre állunk, továbbítjuk válaszunkat, majd pedig lezárjuk a tranzakciós programot.

A programok kipróbálása természetesen történhet egy gépen is. Amennyiben megfelelôen telepítettük a bôvítôcsomagot és frissítettük a Communications Server konfigurációját is, indítsuk el a LECKE03A programot. Ha minden jól megy, akkor be kell gépelnünk a gép LU nevét, amely hatására lefut a LECKE03B program, és a beprogramozott üzenetek kicserélôdnek. Ha látni akarjuk, hogy a LECKE03B mit csinál mûködés közben, akkor írjunk be egy pause-t a "szerver program" Say 'A kliens szövege: 'data.2 sora után. Ha újra futtatjuk a LECKE03A programot, akkor a LU név begépelése után az elôtérbe hozhatjuk a háttérben várakozó LECKE03B programot és megvizsgálhatjuk a megjelenített üzenetet. A két egyszerû példaprogram kitûnô példa arra, hogy hogyan mûködhetnek együtt az SNA hálózat különbözô (jelen esetben OS/2 alatt futó) csomópontjaiban található (REXX) részprogramok, s hogyan képezhetnek egy nagy elosztott alkalmazást.

Az RXAPPCFD bôvítôcsomag

Az RXAPPC Dave Boll által továbbfejlesztett változata az RXAPFD bôvítôcsomag, amelyet egy, a német IBM által még 1996-ban kiadott OS/2 Software Hit CD-n találtam. Az RXAPFD már alkalmas a CM/2 1.1-es verziójában bevezetett full-duplex adatcserére is. Egy másik lényeges bôvítés, hogy a mellékelt EXE2REXX.EXE program felhasználásával a REXX programok a CM attach managerén (amit talán indítóprogramnak lehetne ferdíteni) keresztül legyenek indíthatóak. Ez azt jelenti, hogy ezzel a csomaggal már nem kell a CM aktív konfigurációját tartalmazó NDF fájlban a TP-ket definiálni, ezt automatikusan megoldja egy csatolt segédprogram. Az RXAPFD-ben található függvények nagyon hasonlóak az RXAPPC függvényeihez, ezért ezekre nem térünk ki részletesen. Az RXAPFD-ben található extra függvények fôleg a full-duplex adatcseréhez kellenek.

Bár az RXAPFD többet nyújt, mint az RXAPPC, szerintem mindenképpen érdemes elôször az egyszerûbb RXAPPC-vel megismerkedni.

A CPI-C kiterjesztés

A lecke elején már említettük a CPI kommunikációs programokat, amelyeket REXX nyelven is lehet írni. Ráadásul ehhez semmilyen külsô bôvítômodulra nincs szükség, mivel a Communications Server (Manager) támogatja a CPI API-k REXX-bôl történô meghívását. A többi bôvítômodultól eltérôen a CPI függvényhívásokat nem egy DLL regisztrálása, hanem egy EXE fájl (CPICREXX.EXE) lefuttatása után lehet használni. A programot elég egyszer lefuttatni, ezért ha valaki rendszeresen használ CPI hívásokat REXX-bôl, akkor érdemes beírnia a futtatóparancsot a STARTUP.CMD-be. Amennyiben nem futtatjuk le a CPIREXX-et a REXX program végrehajtása elôtt, akkor a CPI függvényhívásokat nem fogja a REXX értelmezôje felismerni. A REXX program elején kötelezô feldolgoztatni a Communications Server telepítése után a gépen található CMREXX.CPY fájlt, amely a CPI függvények helyes mûködéséhez nélkülözhetetlen definíciókat tartalmazza. A feldolgoztatást megtehetjük az alábbi kódrészlettel:

fn="CMREXX.CPY"
do while lines(fn)
	INTERPRET linein(fn)
end

Természetesen az is jó, ha bemásoljuk a fájl tartalmát a REXX program elejébe. Amennyiben a programot a CM attach managerén keresztül akarjuk futtatni, akkor definiálni kell TP-ként a Communications Server konfigurációjában. A TP definícióban programként a CMD.EXE programot kell megadni. A REXX tranzakciós program a definiált program paramétereként kerülhet megadásra. A futás során lefoglalt erôforrások felszabadítása érdekében fontos, hogy a paraméterek között a /C-t is megadjuk, mivel ekkor az OS/2 automatikusan bezárja a tranzakciós program lefutása után megnyitott szekciót. Ha pl. a CPITEST.CMD tranzakciós programot akarjuk definiálni, akkor a következô programot és paramétereket kell megadnunk:

FILESPEC(cmd.exe)
PARM_STRING(/c CPITEST.CMD)

A CPI API-k a következô általános formában hívhatóak meg:

ADDRESS CPICOMM 'függvényhívás paraméter1 paraméter2 ... paramétern'

A függvények sikeres végrehajtásáról a 0 visszatérési érték tájékoztat. Az ettôl eltérô értékek mindig valamilyen hibát jeleznek:

Visszatérési érték Jelentés
+30 A CPIREXX.EXE program nem lett végrehajtva.
-3 A meghívott függvény ismeretlen.
-9 A függvényhíváshoz szükséges CS puffer lefoglalása nem sikerült.
-10 Túl sok függvényparaméter lett megadva.
-11 Túl kevés függvényparaméter lett megadva.
-24 Fetch failure (ismeretlen változó).
-25 Set failure (REXX memóriaprobléma).
-28 Érvénytelen változónév.

A legjobb eljárás, ha minden függvényhívás után ellenôrizzük a visszatérési értékeket. Ha hiba történt, akkor a függvény által visszaadott változók tartalmának nincs értelme.

Egyes CPI hívások adatstruktúrákkal dolgoznak. Struktúrák nem léteznek REXX-ben, ezért összetett változókat használunk helyettük. Vigyázni kell arra, hogy az összetett változók elemeinek neve megegyezzen az adatstruktúra megfelelô rekordjának nevével, különben az API nem fog mûködni!

Az erôforrások felszabadítása érdekében minden CPI-REXX programot az EXIT utasítással zárjunk le!

Az EHLLAPI kiterjesztés

A Communications Manager terminál emulátor programjai, vagy a PCOM (Personal Communications) program révén lehetôség nyílik arra, hogy egy OS/2-es gép az IBM-es nagygépekkel kommunikáljon a 3270 és/vagy 5250 emuláció révén. A Communications Manager/Server arra is lehetôséget nyújt, hogy REXX programokból manipuláljuk az emulátorszekciókat. Azon API-k gyûjteményét, amelyek ezt a manipulációt lehetôvé teszi, Emulator High-Level Language Application Programming Interface-nek (EHLLAPI) nevezzük.

Mielôtt REXX-bôl használni tudnánk az EHLLAPI függvényeket, regisztrálnunk kell a Communications Manager vagy PCOMM telepítése után a gépre felkerülô SAAHLPAI.DLL-t:

CALL RxFuncAdd 'HLLAPI', 'SAAHLAPI', 'HLLAPISRV'

Az EHLLAPI függvényeket formailag egy függvény (HLLAPI) tartalmazza, amelynek elsô paramétere adja meg, hogy tulajdonképpen melyik függvényrôl van szó. Az alábbi kódrészletben arra láthatunk példát, hogy hogyan kell a hosthoz kapcsolódni:

Rc = HLLAPI('Connect_PM','B')   /* connect to B host session window */

A HLLAPI függvények segítségével el lehet olvasni az emulátor képernyôjén található adatokat, utasításokat lehet küldeni a hostnak, vagy akár fájlokat is lehet cserélni a host és a PC között. A csomaghoz mellékelt INF fájl kimerítôen dokumentálja a használható függvényeket és hasznos példákon keresztül mutatja be alkalmazásukat.

Egyéb CM kiterjesztések

A Communications Manager/Server tartalmaz egy REXXSNA nevû komponenst is, amely segítségével a REXX programok használhatják a CM API-k eddig nem említett részét is. A REXXSNA csomagban lévô függvényeket a következô kódrészlettel lehet regisztrálni:

Call RxFuncAdd 'SNALoadFuncs', 'REXXSNA', 'SNALoadFuncs'
Call SNALoadFuncs

A függvények nagy számára való tekintettel meg sem tudjuk kísérelni, hogy ebben a leckében egyenként bemutassuk ôket. Kárpótlásképpen az alábbi táblázatban összefoglaltuk a függvényekkel elvégezhetô feladatcsoportokat:

Függvénycsoport: Rendeltetés: Példa:
Segédfüggvények Ezekkel a függvényekkel lehet az REXXSNA bôvítôfüggvényeit regisztrálni illetve eltávolítani. SNALoadFuncs
Konfigurációs függvények Ezekkel a függvényekkel lehet a CM konfigurációját megváltoztatni. DefineLocalLU
Konvertáló függvények Ezekkel a függvényekkel lehet karakterkonverziót végezni. Convert
Megjelenítô függvények Ezekkel a függvényekkel lehet mindenféle információt lekérdezni az SNA hálózattal kapcsolatosan. DisplayLUDef
Kernel függvények Ezekkel a függvényekkel lehet a CM kernelt menedzselni. CMQueryService
LUA függvények Ezekkel a függvényekkel lehet az RUI és SLI interfészeket menedzselni. RUIInit
MS függvények Ezekkel a függvényekkel lehet a Management Service (MS) alkalmazásokat használni. RegisterMSAppl
Alrendszer függvények Ezekkel a függvényekkel lehet a CM alrendszereit (pl. attach manager) menedzselni. StartAM

Aki alkalmazni kívánja a REXXSNA függvényeket, az bôséges angol nyelvû információt és rengeteg példaprogram-részletet talál a csomaghoz mellékelt INF fájlban.

 

REXX GYÍK:

K1. Nem mûködik a leckében megadott példaprogram (lecke03a.cmd), pedig a gépemen helyesen konfigurált Communications Manager/Server fut. Indítás után arra panaszkodik a REXX, hogy nem ismeri a programban használt függvények valamelyikét.
V1. Ellenôrizze, hogy a bôvítômodul DLL-je a LIBPATH-ban megtalálható könyvtárban van. Ha nem, akkor másolja oda és futtassa újra a programot.

 

Gyakorlatok:

1. Írja át a példaprogramokat oly módon, hogy azok több, menet közben begépelhetô üzeneteket cseréljenek!

2. Írja át a lecke3b példaprogramot oly módon, hogy az futtatáskor elküldje a gép fontosabb paramétereit (pl. hardverkonfiguráció) a hívó félnek!

Kádár Zsolt
1999. 05. 09.