Ablakok.  Vírusok.  Jegyzetfüzetek.  Internet.  hivatal.  Segédprogramok.  Drivers

Ennek a cikknek a célja a terminológia megvitatása. A cikk nem arról szól, hogyan és miért, hanem csak a terminológia használatáról. A cikk a szerző véleményét tükrözi, és nem állítja, hogy tudományos.

Bevezetés

Ha a programozás területén dolgozik elosztott rendszerek vagy be rendszerintegráció, akkor az itt bemutatottak nagy része nem újdonság számodra.

A probléma akkor merül fel, amikor az emberek találkoznak a használatával különböző technológiákés amikor azok az emberek technikai beszélgetésbe kezdenek. Ilyenkor gyakran a terminológia miatt kölcsönös félreértés adódik. Itt megpróbálom összehozni a különböző kontextusokban használt terminológiákat.

Terminológia

Ezen a területen nincs egyértelmű terminológia és osztályozás. Az alábbiakban használt terminológia a szerző modelljét tükrözi, vagyis szigorúan szubjektív. Bármilyen kritikát és vitát szívesen fogadunk.

A terminológiát három területre osztottam: RPC (Remote Procedure Call), Messaging és REST. Ezeknek a területeknek történelmi gyökerei vannak.

RPC

RPC technológiák a legrégebbi technológiák. Az RPC legfényesebb képviselői: CORBAÉs DCOM.

Akkoriban főleg rendszereket kellett gyorsan és viszonylag megbízhatóan összekapcsolni helyi hálózatok. Az RPC mögött meghúzódó fő gondolat az volt, hogy a távoli rendszerek hívását a programon belüli funkciókhoz hasonlóvá tegyék. Minden távoli hívás mechanika el volt rejtve a programozó elől. Legalább megpróbálták elrejteni. A programozóknak sok esetben mélyebb szinten kellett dolgozniuk, ahol megjelent a marshaling kifejezés ( rendező) És rendezetlen(hogy van ez oroszul?), ami lényegében a szerializálást jelentette. A folyamatokon belüli normál függvényhívásokat a bejövő hívó kezelte meghatalmazott, és a rendszer funkciót ellátó oldalán, in Diszpécser. Ideális esetben sem a hívó rendszer, sem a feldolgozó rendszer nem kezelte a rendszerek közötti adatátvitel bonyolultságát. Mindezek a finomságok a Proxy - Dispatcher csomagban összpontosultak, amelynek kódja automatikusan generált.

Tehát nem fog észrevenni, nem is szabad észrevennie semmi különbséget a helyi függvény és a távoli függvény hívása között.
Most egyfajta RPC reneszánsz van, melynek legkiemelkedőbb képviselői: Google ProtoBuf, Thrift, Avro.

Üzenetküldés

Idővel kiderült, hogy az a kísérlet, hogy megvédjék a programozót attól, hogy a hívott függvény még mindig eltér a helyitől, nem vezetett a kívánt eredményhez. A megvalósítás részletei és az elosztott rendszerek közötti alapvető különbségek túl nagyok voltak ahhoz, hogy automatikusan generált proxykóddal megoldhatóak legyenek. Fokozatosan jött az a felismerés, hogy a programkódban kifejezetten tükröződnie kell annak, hogy a rendszereket megbízhatatlan, lassú, kis sebességű környezet köti össze.

Megjelentek a technológiák webszolgáltatások. Elkezdtünk beszélgetni ABC: Cím, kötés, szerződés. Nem teljesen világos, miért jelentek meg a szerződések, amelyek lényegében borítékok (borítékok) az input argumentumokhoz. A szerződések gyakran inkább bonyolítják az egész modellt, mintsem egyszerűsítik azt. De... mindegy.

Most a programozó kifejezetten létrehozta szolgáltatás(Szolgáltatás) vagy ügyfél(ügyfél), amely felhívja a szolgáltatást. A szolgáltatás készlet volt tevékenységek (művelet), amelyek mindegyike a bemenetnél vett kérés(Kérés) és kiadták válasz(Válasz). ügyfél kifejezetten küldött(Szent) kérésére a szolgáltatás kifejezetten kapott ( kap) és válaszolt (Elküldve), elküldve a választ. Az ügyfél megkapta (Fogadása) a választ, és ezzel a hívás véget ért.

Csakúgy, mint az RPC-ben, itt is működött valahol a Proxy és a Dispatcher. És mint korábban, a kódjuk automatikusan generált, és a programozónak nem kellett értenie. Kivéve, ha az ügyfél kifejezetten a Proxy osztályait használta.

A kérések és válaszok kifejezetten vezetékes formátumra konvertálódnak. Leggyakrabban bájtok tömbje. Az átalakítást ún SorozatosításÉs Deszerializációés néha elbújik a proxy kódban.
Az üzenetküldés csúcspontja egy paradigma megjelenésében nyilvánult meg ESB (Enterprise Service Bus). Senki sem tudja igazán megfogalmazni, hogy mi ez, de abban mindenki egyetért, hogy az ESB-re vonatkozó adatok üzenetek formájában mozognak.

PIHENÉS

A kód összetettségével való folyamatos küzdelemben a programozók megtették a következő lépést és létrehoztak PIHENÉS.

A REST alapelve az, hogy a függvényműveletek erősen korlátozottak, és csak egy műveletsor marad meg. CRUD: Létrehozás - Olvasás - Frissítés - Törlés. Ebben a modellben minden művelet mindig bizonyos adatokra vonatkozik. A CRUD-ban elérhető műveletek a legtöbb alkalmazáshoz elegendőek. Mivel a REST technológiák a legtöbb esetben HTTP protokollt használnak, a CRUD parancsok tükröződnek a parancsokban http (hozzászólás - Kap - Tedd - Töröl) . Folyamatosan azzal érvelnek, hogy a REST nem feltétlenül kapcsolódik a HTTP-hez. A gyakorlatban azonban széles körben használják a műveleti aláírások tükrözését a HTTP-parancsok szintaxisában. Például egy függvényhívás

EntityAddress ReadEntityAddress(string param1, string param2)

Így kifejezve:

GET: entityAddress?param1=value1¶m2=value2

Következtetés

Mielőtt elkezdené az elosztott rendszerekről vagy az integrációról szóló vitát, határozzon meg néhány terminológiát. Ha a proxy mindig ugyanazt jelenti a különböző kontextusokban, akkor például a kérés keveset jelent az RPC szempontjából, és a rendeződés zavart okoz a REST technológiák tárgyalása során.



A hálózaton keresztül kommunikáló programoknak kommunikációs mechanizmusra van szükségük. Az alsó szinten a csomagok megérkezésekor jelet küldenek, feldolgoznak hálózati program jelfeldolgozás. A legfelső szinten az ada nyelvben elfogadott találkozási mechanizmus (rendezvous) működik. Az NFS távoli eljáráshívás (RPC) mechanizmust használ, amelyben az ügyfél kommunikál a szerverrel (lásd: 1. ábra). Ennek a folyamatnak megfelelően a kliens először meghív egy eljárást, amely kérést küld a szervernek. A kérést tartalmazó csomag megérkezésekor a szerver elindítja a nyitási eljárását, végrehajtja a kért szolgáltatást, választ küld, és a vezérlés visszakerül a klienshez.

Az RPC interfész három rétegből áll:

  1. A legfelső szint teljesen "átlátszó". Egy ilyen szintű program tartalmazhatja például az rnusers() eljárás hívását, amely visszaadja a távoli gépen lévő felhasználók számát. Nem kell tudnia az RPC-mechanizmus használatáról, amíg a hívást a programban kezdeményezi.
  2. Átlagos szint a leggyakoribb alkalmazásokhoz tervezték. Az RPC-hívásokat ezen a szinten a registerrpc() és callrpc() szubrutinok kezelik: a registerrpc() rendszerszintű kódot kap, a callrpc() pedig távoli eljáráshívást hajt végre. Az rnusers() hívás e két alprogram segítségével valósul meg.
  3. Az alacsonyabb szintet olyan összetettebb feladatokhoz használják, amelyek az alapértelmezett értékeket módosítják az eljárási paraméterek értékeire. Ezen a szinten kifejezetten módosíthatja az RPC üzenetek küldésére használt socketeket.

Általános szabály, hogy használja a felső szintet, és kerülje az alsó szintek használatát, hacsak nem feltétlenül szükséges.

Annak ellenére, hogy ebben az oktatóanyagban csak a C felülettel foglalkozunk, a távoli eljáráshívások bármilyen nyelvről indíthatók. A különböző gépeken a folyamatok közötti kommunikáció megszervezésére szolgáló RPC mechanizmus működése nem különbözik az ugyanazon a gépen történő működésétől.

Az RPC (Remote Procedure Call, Remote Procedure Call Service) egy interfész a távoli felhasználók és bizonyos gazdaprogramok között, amelyek e felhasználók kérésére indulnak el. A gazdagép RPC szolgáltatása általában egy sor programot biztosít az ügyfelek számára. E programok mindegyike egy vagy több távoli eljárásból áll. Például egy távoli szolgáltatás fájlrendszer Az RPC hívásokra épülő NFS csak két programból állhat: például egy program magas szintű interakcióba lép. felhasználói felületek, a másik pedig alacsony szintű I/O funkciókkal.

Minden távoli eljáráshívásban két fél vesz részt: az aktív kliens, amely eljáráshívási kérelmet küld a szervernek, és a szerver, amely választ küld vissza a kliensnek.

Jegyzet. Vegye figyelembe, hogy a "kliens" és a "szerver" kifejezések a ez az eset konkrét tranzakcióra utalnak Egy adott gazdagép ill szoftver(folyamat vagy program) kliensként és szerverként is működhet. Például egy távoli eljárási szolgáltatást nyújtó program egy hálózati fájlrendszerrel dolgozó kliens is lehet.

Az RPC protokoll a helyi eljáráshívásokhoz hasonló távoli eljáráshívási modellre épül. Ha helyi eljárást hív meg, az argumentumokat a memória egy meghatározott helyére tolja, akár a veremben, akár a veremben Környezeti változókés átadja a folyamat irányítását egy adott címre. Ha elkészült, elolvassa az eredményeket egy adott címen, és folytassa a folyamatot.

Távoli eljárással végzett munka esetén a fő különbség az, hogy a távoli függvényhívást két folyamat szolgálja ki: a kliens folyamat és a szerver folyamat.

A kliens folyamat egy üzenetet küld a szervernek, amely tartalmazza a hívott eljárás paramétereit, és várja a válaszüzenetet a munkája eredményével. Amikor válasz érkezik, a rendszer kiolvassa az eredményt, és a folyamat folytatódik. Szerver oldalon a híváskezelő folyamat várakozó állapotban van, és amikor üzenet érkezik, beolvassa az eljárás paramétereit, végrehajtja azt, választ küld, és a következő hívásra vár.

Az RPC protokoll nem támaszt semmilyen követelményt a folyamatok közötti további kommunikációra, és nem követeli meg a végrehajtott funkciók szinkronizálását, azaz a hívások lehetnek aszinkronok és egymástól függetlenek, így a kliens válaszra várva más eljárásokat is végrehajthat. Az RPC szerver minden funkcióhoz külön folyamatot vagy virtuális gépet tud lefoglalni, így anélkül, hogy megvárná az előző kérések befejezését, azonnal elfogadhatja a következő kéréseket.

Számos fontos különbség van azonban a helyi és a távoli eljáráshívások között:

  1. Hiba a feldolgozásban. A klienst minden esetben értesíteni kell azokról a hibákról, amelyek a szerveren vagy a hálózaton történő távoli eljáráshívások során fordulnak elő.
  2. Globális változók. Mivel a szerver nem fér hozzá az ügyfél címteréhez, a távoli eljáráshívások nem használhatnak rejtett paramétereket globális változóként.
  3. Teljesítmény. A távoli eljárások végrehajtásának sebessége általában egy vagy két nagyságrenddel alacsonyabb, mint a hasonló helyi eljárások végrehajtásának sebessége.
  4. Hitelesítés. Mivel a távoli eljáráshívások a hálózaton keresztül történnek, ügyfél-hitelesítési mechanizmusokat kell használni.

Protokollépítési elvek.

Az RPC protokoll többféle szállítási protokollt is használhat. Az RPC protokoll felelőssége csak a szabványok biztosítása és az üzenettovábbítás értelmezése. Az üzenetátvitel megbízhatóságát és megbízhatóságát teljes mértékben a szállítási réteg biztosítja.

Az RPC azonban képes szabályozni a szállítási protokoll kiválasztását és néhány funkcióját. Példaként az RPC és a szállítási protokoll közötti interakcióra nézzük meg az RPC port hozzárendelését egy alkalmazási folyamathoz az RPC - Portmapper segítségével.

Ez a funkció dinamikusan (igény szerint) egy adott portot rendel egy RPC kapcsolathoz. A Portmapper funkciót elég gyakran használják, mivel az RPC számára fenntartott szállítási portok száma korlátozott, és az egyidejűleg potenciálisan futtatható folyamatok száma nagyon magas. A Portmapper például meghívásra kerül, amikor portokat választunk ki az ügyfél és a szerver kommunikációjához NFS rendszerek.

A Portmapper szolgáltatás az RPC üzenetszórási mechanizmust használja egy adott porton - III. Ezen a porton a kliens portkérés üzenetszórási üzenetet küld egy adott RPC szolgáltatáshoz. A Portmapper szolgáltatás feldolgozza az üzenetet, meghatározza a helyi RPC szolgáltatás címét, és választ küld az ügyfélnek. Az RPC Portmapper szolgáltatás TCP és UDP protokollal is működhet.

Az RPC különféle szállítási protokollokkal tud működni, de soha nem duplikálja meg a funkcióikat, azaz ha az RPC a TCP-n felül működik, az RPC kapcsolat megbízhatóságával és megbízhatóságával kapcsolatos minden aggály a TCP-hez van rendelve. Ha azonban az RPC UDP-n keresztül van telepítve, további natív szolgáltatásokat biztosíthat az üzenetek kézbesítésének biztosítására.

Jegyzet.

Az alkalmazási feladatok az RPC protokollt egy adott eljárásnak tekinthetik egy függvény JSR (Jump Subroutine Instruction) hálózaton keresztüli meghívására.

Az RPC protokoll működéséhez a következő feltételeknek kell teljesülniük:

  1. Az összes távolról hívott eljárás egyedi azonosítása egy adott gazdagépen. Az RPC kérések három azonosító mezőt tartalmaznak - a távoli program (szolgáltatás) számát, a távoli program verziószámát és a távoli eljárás számát. a megadott programot. A programszámot a szolgáltatás gyártója rendeli hozzá, az eljárásszám a szolgáltatás konkrét funkcióját jelzi
  2. Az RPC protokoll verziójának azonosítása. Az RPC üzenetek tartalmaznak egy RPC protokoll verzió mezőt. Arra használják, hogy megállapodjanak a továbbított paraméterek formátumairól, amikor az ügyfél dolgozik vele különböző verziók RPC.
  3. Mechanizmusok biztosítása az ügyfél hitelesítéséhez a szerverhez. Az RPC protokoll eljárást biztosít a kliens hitelesítésére a szolgáltatásban, és ha szükséges, minden kéréssel vagy válasz küldésével az ügyfélnek. Ezenkívül az RPC különféle további biztonsági mechanizmusok használatát teszi lehetővé.

Az RPC négyféle hitelesítési mechanizmust használhat:

  • AUTH_NULL – nincs hitelesítés
  • AUTH_UNIX - UNIX szabványos hitelesítés
  • AUTH_SHORT - UNIX szabványos hitelesítés saját kódolási struktúrával
  • AUTH_DES – DES hitelesítés
  1. A megfelelő kérésekre adott válaszüzenetek azonosítása. Az RPC válaszüzenetek azt a kérésazonosítót tartalmazzák, amelyből készültek. Ezt az azonosítót nevezhetjük az RPC hívás tranzakcióazonosítójának. Ez a mechanizmus különösen akkor szükséges, ha aszinkron üzemmódban dolgozik, és több RPC hívásból álló sorozatot hajt végre.
  2. Protokollhibák azonosítása. Minden hálózati vagy szerverhibának egyedi azonosítója van, amelyek alapján a kapcsolat minden résztvevője meghatározhatja a hiba okát.

Protokoll üzenetszerkezetek

RPC-üzenetek szállítási protokollon keresztül történő továbbításakor több RPC-üzenet is elhelyezhető egyetlen szállítási csomagon belül. Az üzenetek elkülönítésére rekordjelzőt (RM - Record Marker) használnak. Minden RPC-üzenet pontosan egy RM-vel van "címkézve".

Egy RPC üzenet több töredékből is állhat. Mindegyik töredék négy fejlécbájtból és (0-tól 2**31-1-ig) adatokból áll. A fejléc első bitje jelzi, hogy az adott töredék az utolsó, a fennmaradó 31 bit pedig az adatcsomag hosszát.

Az RPC felépítését formálisan az adatformátumok leírásának és megjelenítésének nyelvén - XDR - írja le, az eljárások leírására vonatkozó kiegészítésekkel. Akár azt is mondhatnánk, hogy az RPC leíró nyelv az XDR kiterjesztése, kiegészítve eljárásokkal végzett munkával.

Az RPC-csomag szerkezete így néz ki:


A válaszstruktúra (reply_body) tartalmazhatja vagy a hiba esetén átadott struktúrát (amikor a hibakódot tartalmazza), vagy a sikeres kérésfeldolgozás struktúráját (amikor a visszaadott adatokat tartalmazza).

Magas szintű programozói felület.

A programban a szubrutinok használata a feladat felépítésének, áttekinthetőbbé tételének hagyományos módja. A leggyakrabban használt rutinokat könyvtárakba gyűjtik, ahol különböző programok használhatják őket. Ebben az esetben beszélgetünk egy helyi (helyi) hívásról, azaz a hívó és a hívott objektum is ugyanazon a programon belül működik ugyanazon a számítógépen.

Távoli hívás esetén az egyik számítógépen futó folyamat elindít egy folyamatot a távoli számítógépen (vagyis ténylegesen lefuttatja az eljáráskódot a távoli számítógépen). Nyilvánvaló, hogy egy távoli eljáráshívás jelentősen eltér a hagyományos lokálistól, de a programozó szempontjából gyakorlatilag nincsenek ilyen eltérések, vagyis a távoli eljáráshívás architektúrája lehetővé teszi a helyi hívás szimulálását.

Ha azonban helyi hívás esetén a program paramétereket ad át a meghívott eljárásnak, és a veremen vagy a megosztott memóriaterületeken keresztül kapja meg a munka eredményét, akkor távoli hívás esetén a paraméterek átadása kérés küldéssé válik. a hálózat, és a munka eredménye a bejövő válaszban van.

Ez a megközelítés egy lehetséges alapja az elosztott alkalmazások létrehozásának, és bár sok modern rendszerek ne használja ezt a mechanizmust, az alapfogalmak és kifejezések sok esetben megmaradnak. Az RPC mechanizmus leírásánál hagyományosan a hívó folyamatot kliensnek, az eljárást megvalósító távoli folyamatot pedig szervernek nevezzük.

A távoli eljáráshívás a következő lépéseket tartalmazza:

  1. Az ügyfélprogram helyi hívást indít egy csonk nevű eljáráshoz. Ugyanakkor a kliensnek "úgy tűnik", hogy a csonk meghívásával valójában a szerver eljárást hívja meg. Valójában az ügyfél átadja a szükséges paramétereket a csonknak, és az visszaadja az eredményt. A helyzet azonban nem egészen olyan, mint ahogy az ügyfél elképzeli. A csonk feladata, hogy elfogadja a távoli eljáráshoz szánt argumentumokat, esetleg átalakítsa azokat valamilyen szabványos formátumba, és hálózati kérést hozzon létre. Az argumentumok összecsomagolását és a hálózati kérés lebonyolítását rendezésnek nevezzük.
  2. A hálózati kérés a hálózaton keresztül a következő címre kerül elküldésre távoli rendszer. Ehhez a csonk megfelelő hívásokat használ, például az előző szakaszokban tárgyaltakat. Vegye figyelembe, hogy ebben az esetben különféle szállítási protokollok használhatók, nem csak a TCP / IP családok.
  3. A távoli gazdagépen minden benne történik fordított sorrendben. A kiszolgáló csonkja vár egy kérésre, és amikor megkapja, lekéri a paramétereket - az eljáráshívási argumentumokat. A kinyerés (felbontás) tartalmazhat szükséges átalakításokat (például a bájtok átrendezését).
  4. A csonk meghívja azt a valódi szerver eljárást, amelyhez a kliens kérése szól, átadva neki a hálózaton keresztül kapott argumentumokat.
  5. Az eljárás végrehajtása után a vezérlés visszatér a kiszolgáló csonkjához, átadva neki a szükséges paramétereket. Ahogy az ügyfél csonkja is; a szerver csonkja az eljárás által visszaadott értékeket hálózati válaszüzenetté alakítja, amelyet a hálózaton keresztül küldenek el annak a rendszernek, amelytől a kérés érkezett.
  6. Az operációs rendszer a kapott üzenetet továbbítja a kliens csonkjának, amely a szükséges átalakítás után átadja az értékeket (amelyek a távoli eljárás által visszaadott értékek) a kliensnek, amely ezt normál visszatérésként értelmezi a klienstől. eljárást.

Így az ügyfél szemszögéből távoli eljáráshívást kezdeményez, akárcsak egy helyi esetében. Ugyanez mondható el a szerverről is: az eljárást szabványos módon hívják meg, valamilyen objektum (szerver csonk) meghívja a helyi eljárást, és megkapja az általa visszaadott értékeket. A kliens a csonkot hívható szervereljárásként kezeli, a szerver pedig a saját csonkját veszi fel kliensként.

Így a csonkok képezik az RPC rendszer magját, felelősek a kliens és a távoli szerver közötti üzenetek generálásáért és továbbításáért (eljárás) még akkor is, ha mind a kliens, mind a szerver úgy tekinti, hogy a hívások helyben bonyolódnak le. Ez az RPC fő koncepciója – az interakció elosztott (hálózati) jellegének teljes elrejtése a csonkkódban. Ennek a megközelítésnek az előnyei nyilvánvalóak: mind a kliens, mind a szerver független a hálózati megvalósítástól, mindkettő egy meghatározott elosztott hálózaton belül működik. Virtuális gép, és az eljáráshívások szabványos interfésszel rendelkeznek.

Paraméterek átadása

Az értékparaméterek átadása nem nehéz. Ebben az esetben az ügyfélcsonk elhelyezi a paraméter értékét a hálózati kérésben, esetleg szabványos konverziók végrehajtásával (például a végpont megváltoztatásával). Sokkal bonyolultabb a helyzet a mutatók átadásával, amikor a paraméter az adatok címe, nem pedig az értéke. Egy cím átadása a kérelemben értelmetlen, mert a távoli eljárás teljesen más címtérben fut. a legtöbben egyszerű megoldás Az RPC-ben az a célja, hogy megakadályozza az ügyfeleket abban, hogy az értéktől eltérő paramétereket adjanak át, bár ez természetesen komoly korlátozásokat támaszt.

Kötés

Mielőtt egy kliens meghívhatna egy távoli eljárást, hozzá kell rendelni egy távoli rendszerhez, amely rendelkezik a szükséges szerverrel. Így a kötés feladata két részre oszlik:

  1. Távoli gazdagép keresése a kívánt szerverrel
  2. A szükséges szerverfolyamat megkeresése egy adott gazdagépen

Különféle megközelítések használhatók a gazda megtalálására. Lehetséges változat- valamilyen központi címtár létrehozása, amelyben a gazdagépek bejelentik szervereiket, és ahol a kliens igény szerint kiválaszthatja a számára megfelelő állomást és az eljárás címét.

Minden RPC-eljárás egyedileg azonosítható egy program- és eljárásszám alapján. A programszám a távoli eljárások egy csoportját határozza meg, amelyek mindegyikének saját száma van. Minden programhoz hozzá van rendelve egy verziószám is, így ha kisebb változtatásokat hajt végre a programon (például eljárást ad hozzá), akkor nem kell a számát módosítani. Jellemzően több funkcionálisan hasonló eljárás kerül megvalósításra egy programmodulban, amely indításkor ezen eljárások szerverévé válik, és amelyet a programszám azonosít.

Így amikor egy ügyfél távoli eljárást szeretne hívni, ismernie kell a kívánt szolgáltatást biztosító programot, verziót és eljárásszámokat.

A kérés elküldéséhez az ügyfélnek ismernie kell a gazdagép hálózati címét és a szükséges eljárásokat biztosító kiszolgálóprogramhoz társított portszámot is. Ez a portmap(IM) démon segítségével történik (egyes rendszereken rpcbind(IM) néven). A démon olyan gazdagépen fut, amely távoli eljárásszolgáltatást biztosít, és jól ismert portszámot használ. A szerverfolyamat inicializálásakor regisztrálja eljárásait és portszámait a portmap(IM)-ben. Most, amikor az ügyfélnek tudnia kell a portszámot egy adott eljárás meghívásához, kérést küld a portmap(IM) szervernek, amely viszont vagy visszaadja a portszámot, vagy közvetlenül továbbítja a kérést a távoli eljáráskiszolgálónak, és válasz az ügyfélnek, amikor végrehajtja. Mindenesetre, ha a szükséges eljárás létezik, a kliens megkapja az eljárás portszámát a portmap(IM) szervertől, és közvetlenül erre a portra küldhet további kéréseket.

Különleges helyzetek kezelése (kivétel)

A kivételek kezelése helyi eljárások hívásakor nem jelent nagy problémát. A UNIX biztosítja a folyamathibák kezelését, mint például a nullával való osztás, az érvénytelen memóriaterülethez való hozzáférés stb. Távoli eljáráshívás esetén megnő a hibahelyzetek valószínűsége. A kiszolgáló- és csonkhibákhoz hozzáadódnak azok a hibák, amelyek például egy hibás hálózati üzenet fogadásához kapcsolódnak.

Például, ha az UDP-t átviteli protokollként használja, az üzenetek egy bizonyos időtúllépés után újraküldésre kerülnek. A kliens hibaüzenetet küld, ha bizonyos számú próbálkozás után nem érkezik válasz a szervertől. TCP protokoll használata esetén hibaüzenetet küld a kliensnek, ha a szerver megszakította a TCP-kapcsolatot.

Hívja a Szemantikát

Egy helyi eljárás meghívása egyértelműen a végrehajtásához vezet, majd a vezérlés visszatér a főprogramhoz. Más a helyzet távoli eljárás hívásakor. Lehetetlen meghatározni, hogy pontosan mikor hajtják végre az eljárást, egyáltalán elvégzik-e, és ha igen, hányszor? Például, ha a kérést a távoli rendszer a kiszolgálóprogram összeomlása után kapja meg, az eljárás egyáltalán nem kerül végrehajtásra. Ha az ügyfél egy bizonyos idő elteltével nem kap választ (időtúllépés), újra elküldi a kérést, akkor olyan helyzet állhat elő, amikor a válasz már továbbításra kerül a hálózaton, és az ismételt kérést a távoli eljárás újra elfogadja feldolgozásra. . Ebben az esetben az eljárást többször is végrehajtják.

Így egy távoli eljárás végrehajtása a következő szemantikával jellemezhető:

  • Egyszer és csak egyszer. Ezt a viselkedést (bizonyos esetekben a legkívánatosabb) nehéz megkövetelni az esetleges szerverösszeomlások miatt.
  • Maximum idők. Ez azt jelenti, hogy az eljárást vagy egyáltalán nem, vagy csak egyszer hajtották végre. Hasonló állítás tehető, ha normál válasz helyett hibát kap.
  • Legalább egyszer. Az eljárást valószínűleg egyszer végezték el, de több is lehetséges. Ilyen helyzetben a normál működéshez a távoli eljárásnak rendelkeznie kell az idempotens tulajdonsággal (az angol idemponentből). Ennek a tulajdonságnak van egy eljárása, amelynek ismételt végrehajtása nem okoz halmozott változásokat. Például egy fájl olvasása idempotens, de szöveg hozzáadása egy fájlhoz nem.

Adatábrázolás

Ha a kliens és a kiszolgáló ugyanazon a rendszeren fut ugyanazon a számítógépen, nincs adat-inkompatibilitási probléma. Mind a kliens, mind a szerver esetében az adatok bináris formában jelennek meg azonos módon. Távoli hívás esetén a dolgot bonyolítja, hogy a kliens és a szerver különböző architektúrájú rendszereken futhatnak, amelyek eltérő adatreprezentációval rendelkeznek (például lebegőpontos érték ábrázolása, végpontosság stb.).

Az RPC rendszer legtöbb implementációja meghatároz néhány szabványos adatreprezentációt, amelyre a kérésekben és válaszokban átadott összes értéket át kell alakítani.

Például a Sun Microsystems RPC adatábrázolási formátuma a következő:

  1. Byte Order – Legnagyobb utolsó
  2. Lebegőpontos értékeket képvisel - IEEE
  3. Karakterábrázolás - ASCII

Háló

Funkcionalitásában az RPC rendszer egy köztes helyet foglal el az alkalmazási réteg és a szállítási réteg között. Az OSI-modellnek megfelelően ez a rendelkezés megfelel a prezentációs és a munkamenet rétegeknek. Így az RPC elméletileg független a hálózat megvalósításától, különösen a szállítási réteg hálózati protokolljaitól.

A rendszer szoftveres megvalósításai általában egy vagy két protokollt támogatnak. Például a Sun Microsystems RPC rendszere támogatja az üzenettovábbítást a TCP és UDP protokollok használatával. Az egyik vagy másik protokoll kiválasztása az alkalmazás követelményeitől függ. Az UDP protokoll választása indokolt az alábbi jellemzőkkel rendelkező alkalmazásoknál:

  • A hívott eljárások idempotensek
  • Az átadott argumentumok és a visszaadott eredmény mérete kisebb, mint az UDP-csomag mérete - 8 KB.
  • A szerver több száz klienssel biztosít munkát. Mivel a szerver minden aktív klienssel kénytelen kapcsolatot fenntartani, amikor TCP protokollokkal dolgozik, ez erőforrásainak jelentős részét lefoglalja. Az UDP protokoll kevésbé erőforrásigényes ebből a szempontból.

Másrészt a TCP lehetővé teszi a következő jellemzőkkel rendelkező alkalmazások hatékony működését:

  • Az alkalmazás megbízható átviteli protokollt igényel
  • A meghívott eljárások nem-idemponentesek
  • Az argumentumok vagy a visszatérési eredmény mérete meghaladja a 8 KB-ot

A protokoll megválasztása általában a kliensnél marad, és a rendszer különböző módokon szervezi meg az üzenetek kialakítását és továbbítását. Tehát a TCP protokoll használatakor, amelyhez az átvitt adat egy bájtfolyam, el kell különíteni az üzeneteket egymástól. Ehhez például az RFC1057-ben leírt "RPC: Remote Procedure Call Protocol Specifikation version 2" rekordjelölő protokollt használják, amelyben minden üzenet elejére egy 32 bites egész szám kerül, amely megadja az üzenet méretét. bájtokban.

Más a helyzet a hívás szemantikájával. Például, ha az RPC megbízhatatlan szállítási protokoll (UDP) használatával történik, a rendszer rövid időközönként (időtúllépések) újraküldi az üzenetet. Ha az ügyfélalkalmazás nem kap választ, akkor nyugodtan kijelenthető, hogy az eljárást nulla ill több egyszer. Ha válasz érkezett, az alkalmazás arra következtethet, hogy az eljárást legalább egyszer elvégezték. A Trusted Transport Protocol (TCP) esetén válasz érkezésekor elmondható, hogy az eljárást egyszer hajtották végre. Ha nem érkezik meg a válasz, nem lehet egyértelműen kijelenteni, hogy az eljárást nem hajtották végre3.

Hogyan működik?

Lényegében maga az RPC rendszer a kliensprogramba és a szerverprogramba van beépítve. A jó hír az, hogy az elosztott alkalmazások fejlesztése során nem kell elmélyedni az RPC protokoll vagy a program üzenetfeldolgozás részleteiben. A rendszer feltételezi a megfelelő fejlesztői környezet meglétét, ami nagyban leegyszerűsíti az alkalmazásszoftverek készítőinek életét. Az RPC egyik kulcsfontosságú pontja, hogy az elosztott alkalmazás fejlesztése az objektum interfész meghatározásával kezdődik – a szerver funkcióinak formális leírásával. speciális nyelv. Ezen az interfészen alapulva automatikusan létrejönnek a kliens és a szerver csonkok. Ezután már csak a tényleges eljáráskódot kell megírni.

Példaként vegye figyelembe a Sun Microsystems RPC-jét. A rendszer három fő részből áll:

  • Az rpcgen(1) egy RPC fordító, amely a távoli eljárási felület leírása alapján kliens és szerver csonkokat állít elő C programok formájában.
  • XDR (eXternal Data Representation) könyvtár, amely az átalakításhoz szükséges függvényeket tartalmazza különféle típusok az adatokat géptől független formába állítani, lehetővé téve a heterogén rendszerek közötti információcserét.
  • A rendszer egészének működését biztosító modulok könyvtára.

Nézzünk egy példát a legegyszerűbb elosztott eseménynaplózó alkalmazásra. Az ügyfél indításkor egy távoli eljárást hív meg, hogy üzenetet írjon a távoli számítógép naplófájljába.

Ehhez legalább három fájlt kell létrehoznia: a log.x távoli eljárási felületek specifikációját (az interfészleíró nyelven), a log.c távoli eljárások tényleges szövegét és a kliens főoldalának szövegét. program fő () - kliens.c (C nyelven).

Az rpcgen(l) fordító három fájlt hoz létre a log.x specifikáció alapján: a kliens és a szerver csonkjainak szövegét C nyelven (log clnt.c és log svc.c), valamint a mindkét csonk által használt log.h leíró fájlt. .

Nézzük tehát a programok forráskódját.

Ez a fájl adja meg a távoli eljárás regisztrációs paramétereit - program, verzió és eljárásszámokat, valamint meghatározza a hívási felületet - a bemeneti argumentumokat és a visszatérési értékeket. Így az RLOG eljárás definiálva van, és argumentumként egy karakterláncot vesz fel (amely a naplóba kerül), és a visszatérési érték alapértelmezés szerint a kért művelet sikerességét vagy sikertelenségét jelzi.


program LOG_PROG( változat LOG_VER( int RLOG (karakterlánc) = 1; ) = 1; ) = 0x31234567;

Az rpcgen(l) fordító létrehoz egy log.h fejlécfájlt, ahol különösen az eljárások vannak meghatározva:


Nézzük meg közelebbről ezt a fájlt. A fordító az interfészdefiníciós fájlban definiált RLOG nevet rlog_1-re fordítja le, a nagybetűket kisbetűkre cseréli, a program verziószámát pedig aláhúzással fűzi hozzá. A visszatérési típus int-ről int *-ra változott. Ez a szabály – az RPC csak az interfész leírásában deklarált paraméterek címeinek küldését és fogadását teszi lehetővé. Ugyanez a szabály vonatkozik az argumentumként átadott karakterláncra is. Bár a print.h fájl ezt nem jelenti, valójában a sor címe is átadásra kerül argumentumként az rlog_l () függvénynek.

A fejlécfájl mellett az rpcgen(l) fordító kliens csonk és szerver csonkmodulokat is előállít. Lényegében ezeknek a fájloknak a szövege tartalmazza az összes távoli híváskódot.

A szerver csonk az a gazdagép program, amely az ügyféllel (pontosabban a csonkjával) való összes hálózati interakciót kezeli. A művelet végrehajtásához a kiszolgáló csonkja egy helyi függvényhívást hajt végre, melynek szövegét be kell írni:


A kliens csonk átveszi a távoli eljárásnak átadott argumentumot, elvégzi a szükséges átalakításokat, kérelmet küld a portmap(1M) szervernek, kommunikál a távoli eljáráskiszolgálóval, és végül továbbadja a visszatérési értéket a kliensnek. Az ügyfél számára a távoli eljárás hívása csonk hívására redukálódik, és nem különbözik a szokásos helyi hívástól.

ügyfél.c


#beleértve #beleértve"log.h" fő-(int argc, char*argv) ( CLIENT *cl; char*szerver, *mystring, *clnttime; time_tbintime; int*eredmény; ha(argc != 2) ( fprintf(stderr, "Hívás formátuma: %s HostAddr\n", argv ); kilépés (1) ; ) szerver = argv ; /* Szerezze be az ügyfélfogadást. Hiba esetén jelentjük, hogy a szerverrel nem lehet kapcsolatot létesíteni */ ha((c1 = clnt_create (szerver, LOG_PROG, LOG_VER, "udp")) == NULL) ( clnt_pcreateerror (szerver); kilépés (2); ) /*Puffer lefoglalása a karakterlánchoz*/ rejtély = ( char*)malloc(100); /*Határozza meg az esemény időpontját*/ bintime = idő((idő_t *) NULL); clnttime = ctime(&bintime); sprintf(mystring, "%s - Az ügyfél elindult", clnttime); /*Üzenetet küldünk a naplóhoz - az ügyfél munkakezdésének időpontjáról. Hiba esetén jelezzük a hibát */ ha((eredmény = rlog_l(&mystring, cl)) == NULLA) ( fprintf(stderr, "error2\n"); clnt_perror(cl, szerver); exit(3); ) /*A távoli számítógép meghibásodása esetén hibajelentés*/ ha(*eredmény !=0) fprintf(stderr, "Hiba a napló írása közben\n"); /*0szabadítsd ki a fogantyút*/ cint rombol(cl); kilépés(0); )

A log_clnt.c ügyfélcsonk a client.c modullal van lefordítva, hogy egy kliens végrehajtható fájlt hozzon létre.


Most néhány host server.nowhere.ru webhelyen el kell indítania a szerverfolyamatot:


$ logger

Ezt követően, amikor az rlog klienst egy másik gépen elindítják, a szerver hozzáadja a megfelelő bejegyzést a naplófájlhoz.

Az RPC működési sémája ebben az esetben az ábrán látható. 1. A modulok a következőképpen működnek együtt:

  1. Amikor egy szerverfolyamat elindul, létrehoz egy UDP socketet, és minden helyi portot ehhez a sockethez köt. Ezután a szerver meghívja az svc_register(3N) függvénytárat a programszámok és -verziók regisztrálásához. Ehhez a függvény meghívja a portmap(IM) folyamatot, és átadja a szükséges értékeket. A portmap(IM) szerver általában a rendszer inicializálása után indul el, és valamilyen jól ismert porthoz kötődik. Most a portmap(3N) tudja a programunk és verziónk portszámát. A szerver kérés fogadására vár. Vegye figyelembe, hogy az összes leírt műveletet az rpcgen(IM) fordító által létrehozott kiszolgálócsonk hajtja végre.
  2. Amikor az rlog program elindul, először meghívja a clnt_create(3N) függvénykönyvtárat, megadva a távoli rendszer címét, a program- és verziószámokat, valamint a szállítási protokollt. A függvény kérést küld a távoli rendszerszerver.nowhere.m portmap(IM) szerverének, és lekéri a naplószerver távoli portszámát.
  3. Az ügyfél meghívja a kliens csonkjában meghatározott rlog_1() eljárást, és átadja a vezérlést a csonknak. Ez viszont kérést képez (az argumentumok XDR formátumba konvertálásával) UDP-csomag formájában, és elküldi azt a portmap (IM) szervertől kapott távoli portra. Ezután egy ideig vár a válaszra, és ha nem érkezik meg, újra elküldi a kérést. Kedvező körülmények között a kérést a naplózó szerver (szerver csonkmodul) elfogadja. A csonk meghatározza, hogy melyik függvényt hívták meg (az eljárás száma alapján), és meghívja a log.c modul rlog_1() függvényét. Miután visszaadta a vezérlést a csonknak, a csonk az rlog_1 () függvény által visszaadott értéket XDR formátumba konvertálja, és szintén UDP-csomag formájában választ generál. A válasz kézhezvétele után a kliens csonk kivonja a visszaadott értéket, átalakítja és visszaküldi a kliens főprogramjába.

A hálózaton keresztül kommunikáló programoknak kommunikációs mechanizmusra van szükségük. Az alsó szinten a csomagok beérkezésekor jelet küldenek, amelyet a hálózati jelfeldolgozó program dolgoz fel. A legfelső szinten az ada nyelvben elfogadott találkozási mechanizmus (rendezvous) működik. Az NFS távoli eljáráshívás (RPC) mechanizmust használ, amelyben az ügyfél kommunikál a szerverrel (lásd: 1. ábra). Ennek a folyamatnak megfelelően a kliens először meghív egy eljárást, amely kérést küld a szervernek. A kérést tartalmazó csomag megérkezésekor a szerver elindítja a nyitási eljárását, végrehajtja a kért szolgáltatást, választ küld, és a vezérlés visszakerül a klienshez.

Az RPC interfész három rétegből áll:

A legfelső szint teljesen "átlátszó". Egy ilyen szintű program tartalmazhatja például az rnusers() eljárás hívását, amely visszaadja a távoli gépen lévő felhasználók számát. Nem kell tudnia az RPC-mechanizmus használatáról, amíg a hívást a programban kezdeményezi.

A középső szint a leggyakoribb alkalmazásokhoz való. Az RPC-hívásokat ezen a szinten a registerrpc() és callrpc() szubrutinok kezelik: a registerrpc() rendszerszintű kódot kap, a callrpc() pedig távoli eljáráshívást hajt végre. Az rnusers() hívás e két alprogram segítségével valósul meg.

Az alacsonyabb szintet olyan összetettebb feladatokhoz használják, amelyek az alapértelmezett értékeket módosítják az eljárási paraméterek értékeire. Ezen a szinten kifejezetten módosíthatja az RPC üzenetek küldésére használt socketeket.

Általános szabály, hogy használja a felső szintet, és kerülje az alsó szintek használatát, hacsak nem feltétlenül szükséges.

Annak ellenére, hogy ebben az oktatóanyagban csak a C felülettel foglalkozunk, a távoli eljáráshívások bármilyen nyelvről indíthatók. A különböző gépeken a folyamatok közötti kommunikáció megszervezésére szolgáló RPC mechanizmus működése nem különbözik az ugyanazon a gépen történő működésétől.

Az RPC (Remote Procedure Call, Remote Procedure Call Service) egy interfész a távoli felhasználók és bizonyos gazdaprogramok között, amelyek e felhasználók kérésére indulnak el. A gazdagép RPC szolgáltatása általában egy sor programot biztosít az ügyfelek számára. E programok mindegyike egy vagy több távoli eljárásból áll. Például egy távoli NFS-szolgáltatás, amely RPC-hívásokra épül, csak két programból állhat: például az egyik program magas szintű felhasználói felületekkel, a másik pedig alacsony szintű I/O-funkciókkal működik együtt.

Minden távoli eljáráshívásban két fél vesz részt: az aktív kliens, amely eljáráshívási kérelmet küld a szervernek, és a szerver, amely választ küld vissza a kliensnek.

Jegyzet. Ne feledje, hogy a "kliens" és a "szerver" kifejezések ebben az esetben egy adott tranzakcióra utalnak. Egy adott gazdagép vagy szoftver (folyamat vagy program) egyaránt működhet kliensként és szerverként. Például egy távoli eljárási szolgáltatást nyújtó program egy hálózati fájlrendszerrel dolgozó kliens is lehet.

Az RPC protokoll a helyi eljáráshívásokhoz hasonló távoli eljáráshívási modellre épül. Amikor egy helyi eljárást hív meg, az argumentumokat a memória, a verem vagy a környezeti változók egy meghatározott helyére helyezi, és a folyamat irányítását egy adott címre adja át. Ha elkészült, elolvassa az eredményeket egy adott címen, és folytassa a folyamatot.

Távoli eljárással végzett munka esetén a fő különbség az, hogy a távoli függvényhívást két folyamat szolgálja ki: a kliens folyamat és a szerver folyamat.

A kliens folyamat egy üzenetet küld a szervernek, amely tartalmazza a hívott eljárás paramétereit, és várja a válaszüzenetet a munkája eredményével. Amikor válasz érkezik, a rendszer kiolvassa az eredményt, és a folyamat folytatódik. Szerver oldalon a híváskezelő folyamat várakozó állapotban van, és amikor üzenet érkezik, beolvassa az eljárás paramétereit, végrehajtja azt, választ küld, és a következő hívásra vár.

Az RPC protokoll nem támaszt semmilyen követelményt a folyamatok közötti további kommunikációra, és nem követeli meg a végrehajtott funkciók szinkronizálását, azaz a hívások lehetnek aszinkronok és egymástól függetlenek, így a kliens válaszra várva más eljárásokat is végrehajthat. Az RPC szerver minden funkcióhoz külön folyamatot vagy virtuális gépet tud lefoglalni, így anélkül, hogy megvárná az előző kérések befejezését, azonnal elfogadhatja a következő kéréseket.

Számos fontos különbség van azonban a helyi és a távoli eljáráshívások között:

1. Hiba a feldolgozásban. A klienst minden esetben értesíteni kell azokról a hibákról, amelyek a szerveren vagy a hálózaton történő távoli eljáráshívások során fordulnak elő.

2. Globális változók. Mivel a szerver nem fér hozzá az ügyfél címteréhez, a távoli eljáráshívások nem használhatnak rejtett paramétereket globális változóként.

3. Teljesítmény. A távoli eljárások végrehajtásának sebessége általában egy vagy két nagyságrenddel alacsonyabb, mint a hasonló helyi eljárások végrehajtásának sebessége.

4. Hitelesítés. Mivel a távoli eljáráshívások a hálózaton keresztül történnek, ügyfél-hitelesítési mechanizmusokat kell használni.

Protokollépítési elvek.

Az RPC protokoll többféle szállítási protokollt is használhat. Az RPC protokoll felelőssége csak a szabványok biztosítása és az üzenettovábbítás értelmezése. Az üzenetátvitel megbízhatóságát és megbízhatóságát teljes mértékben a szállítási réteg biztosítja.

Az RPC azonban képes szabályozni a szállítási protokoll kiválasztását és néhány funkcióját. Példaként az RPC és a szállítási protokoll közötti interakcióra tekintse meg az alkalmazási folyamat RPC-portjának RPC-n keresztüli hozzárendelését. Portmapper.

Ez a funkció dinamikusan (igény szerint) egy adott portot rendel egy RPC kapcsolathoz. Funkció Portmapper meglehetősen gyakran használják, mivel az RPC számára fenntartott szállítási portok száma korlátozott, és az egyidejűleg működő folyamatok száma nagyon magas. Portmapper Például az NFS-rendszer kliens és szerver kommunikációs portjainak kiválasztásakor hívódik meg.

Szolgáltatás Portmapper az RPC üzenetszórási mechanizmust használja egy adott porton - III. Ezen a porton a kliens portkérés üzenetszórási üzenetet küld egy adott RPC szolgáltatáshoz. Szolgáltatás Portmapper feldolgozza az üzenetet, meghatározza a helyi RPC szolgáltatás címét, és választ küld az ügyfélnek. Szolgáltatás RPC Portmapper TCP és UDP protokollal is működhet.

Az RPC különféle szállítási protokollokkal tud működni, de soha nem duplikálja meg a funkcióikat, azaz ha az RPC a TCP-n felül működik, az RPC kapcsolat megbízhatóságával és megbízhatóságával kapcsolatos minden aggály a TCP-hez van rendelve. Ha azonban az RPC UDP-n keresztül van telepítve, további natív szolgáltatásokat biztosíthat az üzenetek kézbesítésének biztosítására.

Jegyzet. Az alkalmazási feladatok az RPC protokollt egy adott eljárásnak tekinthetik egy függvény JSR (Jump Subroutine Instruction) hálózaton keresztüli meghívására.

Az RPC protokoll működéséhez a következő feltételeknek kell teljesülniük:

1. Egy adott gazdagépen található összes távolról hívott eljárás egyedi azonosítása. Az RPC kérések három azonosító mezőt tartalmaznak - a távoli program (szolgáltatás) számát, a távoli program verziószámát és a megadott program távoli eljárásának számát. A programszámot a szolgáltatás gyártója rendeli hozzá, az eljárásszám a szolgáltatás konkrét funkcióját jelzi

2. Az RPC protokoll verziójának azonosítása. Az RPC üzenetek tartalmaznak egy RPC protokoll verzió mezőt. A továbbított paraméterek formátumának koordinálására szolgál, amikor a kliens az RPC különböző verzióival dolgozik.

3. Mechanizmusok biztosítása a kliens hitelesítéshez a szerveren. Az RPC protokoll eljárást biztosít a kliens hitelesítésére a szolgáltatásban, és ha szükséges, minden kéréssel vagy válasz küldésével az ügyfélnek. Ezenkívül az RPC különféle további biztonsági mechanizmusok használatát teszi lehetővé.

Az RPC négyféle hitelesítési mechanizmust használhat:

AUTH_NULL – nincs hitelesítés

AUTH_UNIX - UNIX szabványos hitelesítés

AUTH_SHORT - UNIX szabványos hitelesítés saját kódolási struktúrával

AUTH_DES – DES hitelesítés

4. A megfelelő kérésekre adott válaszüzenetek azonosítása. Az RPC válaszüzenetek azt a kérésazonosítót tartalmazzák, amelyből készültek. Ezt az azonosítót nevezhetjük az RPC hívás tranzakcióazonosítójának. Ez a mechanizmus különösen akkor szükséges, ha aszinkron üzemmódban dolgozik, és több RPC hívásból álló sorozatot hajt végre.

5. A protokoll működési hibáinak azonosítása. Minden hálózati vagy szerverhibának egyedi azonosítója van, amelyek alapján a kapcsolat minden résztvevője meghatározhatja a hiba okát.

Protokoll üzenetszerkezetek

RPC-üzenetek szállítási protokollon keresztül történő továbbításakor több RPC-üzenet is elhelyezhető egyetlen szállítási csomagon belül. Az üzenetek elkülönítésére rekordjelzőt (RM - Record Marker) használnak. Minden RPC-üzenet pontosan egy RM-vel van "címkézve".

Egy RPC üzenet több töredékből is állhat. Mindegyik töredék négy fejlécbájtból és (0-tól 2**31-1-ig) adatokból áll. A fejléc első bitje jelzi, hogy az adott töredék az utolsó, a fennmaradó 31 bit pedig az adatcsomag hosszát.

Az RPC felépítését formálisan az adatformátumok leírásának és megjelenítésének nyelvén - XDR - írja le, az eljárások leírására vonatkozó kiegészítésekkel. Akár azt is mondhatnánk, hogy az RPC leíró nyelv az XDR kiterjesztése, kiegészítve eljárásokkal végzett munkával.

Az RPC-csomag szerkezete így néz ki:

struct rpc_msg (

unsigned int xid;

union switch (msg_type mtype) (

call_body cbody;

válasz test rbody;

ahol xid az aktuális tranzakció azonosítója, a call_body a kéréscsomag, a válasz_test a válaszcsomag. A kérés szerkezete valahogy így néz ki:

struct call body(

unsigned int rpcvers;

unsigned int prog;

unsigned int vers;

unsigned int proc;

opaque_auth cred;

opaque_authverf;

/* eljárás paraméterei */

A válaszstruktúra (reply_body) tartalmazhatja vagy a hiba esetén átadott struktúrát (amikor a hibakódot tartalmazza), vagy a sikeres kérésfeldolgozás struktúráját (amikor a visszaadott adatokat tartalmazza).

Magas szintű programozói felület.

A programban a szubrutinok használata a feladat felépítésének, áttekinthetőbbé tételének hagyományos módja. A leggyakrabban használt rutinokat könyvtárakba gyűjtik, ahol különböző programok használhatják őket. Ebben az esetben helyi (helyi) hívásról beszélünk, azaz a hívó és a hívott objektumok is ugyanazon a programon belül, ugyanazon a számítógépen működnek.

Távoli hívás esetén az egyik számítógépen futó folyamat elindít egy folyamatot a távoli számítógépen (vagyis ténylegesen lefuttatja az eljáráskódot a távoli számítógépen). Nyilvánvaló, hogy egy távoli eljáráshívás jelentősen eltér a hagyományos lokálistól, de a programozó szempontjából gyakorlatilag nincsenek ilyen eltérések, vagyis a távoli eljáráshívás architektúrája lehetővé teszi a helyi hívás szimulálását.

Ha azonban helyi hívás esetén a program paramétereket ad át a meghívott eljárásnak, és a veremen vagy a megosztott memóriaterületeken keresztül kapja meg a munka eredményét, akkor távoli hívás esetén a paraméterek átadása kérés küldéssé válik. a hálózat, és a munka eredménye a bejövő válaszban van.

Ez a megközelítés egy lehetséges alap az elosztott alkalmazások létrehozásához, és bár sok modern rendszer nem használja ezt a mechanizmust, az alapfogalmak és kifejezések sok esetben megmaradnak. Az RPC mechanizmus leírásánál hagyományosan a hívó folyamatot kliensnek, az eljárást megvalósító távoli folyamatot pedig szervernek nevezzük.

A távoli eljáráshívás a következő lépéseket tartalmazza:

1. Az ügyfélprogram helyi hívást indít egy csonk nevű eljáráshoz. Ugyanakkor a kliensnek "úgy tűnik", hogy a csonk meghívásával valójában a szerver eljárást hívja meg. Valójában az ügyfél átadja a szükséges paramétereket a csonknak, és az visszaadja az eredményt. A helyzet azonban nem egészen olyan, mint ahogy az ügyfél elképzeli. A csonk feladata, hogy elfogadja a távoli eljáráshoz szánt argumentumokat, esetleg átalakítsa azokat valamilyen szabványos formátumba, és hálózati kérést hozzon létre. Az argumentumok összecsomagolását és a hálózati kérés lebonyolítását rendezésnek nevezzük.

2. A hálózati kérés elküldésre kerül a hálózaton keresztül a távoli rendszernek. Ehhez a csonk megfelelő hívásokat használ, például az előző szakaszokban tárgyaltakat. Vegye figyelembe, hogy ebben az esetben különféle szállítási protokollok használhatók, nem csak a TCP / IP családok.

3. A távoli gazdagépen minden fordított sorrendben történik. A kiszolgáló csonkja vár egy kérésre, és amikor megkapja, lekéri a paramétereket - az eljáráshívási argumentumokat. A kinyerés (felbontás) tartalmazhat szükséges átalakításokat (például a bájtok átrendezését).

4. A csonk meghívja azt a valódi szerver eljárást, amelyhez a kliens kérése szól, átadva neki a hálózaton keresztül kapott argumentumokat.

5. Az eljárás végrehajtása után a vezérlés visszatér a kiszolgáló csonkjához, átadva neki a szükséges paramétereket. Ahogy az ügyfél csonkja is; a szerver csonkja az eljárás által visszaadott értékeket hálózati válaszüzenetté alakítja, amelyet a hálózaton keresztül küldenek el annak a rendszernek, amelytől a kérés érkezett.

6. Az operációs rendszer a kapott üzenetet továbbítja a kliens csonknak, amely a szükséges átalakítás után átadja az értékeket (amelyek a távoli eljárás által visszaadott értékek) a kliensnek, amely ezt normál visszatérésként értelmezi. az eljárásból.

Így az ügyfél szemszögéből távoli eljáráshívást kezdeményez, akárcsak egy helyi esetében. Ugyanez mondható el a szerverről is: az eljárást szabványos módon hívják meg, valamilyen objektum (szerver csonk) meghívja a helyi eljárást, és megkapja az általa visszaadott értékeket. A kliens a csonkot hívható szervereljárásként kezeli, a szerver pedig a saját csonkját veszi fel kliensként.

Így a csonkok képezik az RPC rendszer magját, felelősek a kliens és a távoli szerver közötti üzenetek generálásáért és továbbításáért (eljárás) még akkor is, ha mind a kliens, mind a szerver úgy tekinti, hogy a hívások helyben bonyolódnak le. Ez az RPC fő koncepciója – az interakció elosztott (hálózati) jellegének teljes elrejtése a csonkkódban. Ennek a megközelítésnek az előnyei nyilvánvalóak: mind a kliens, mind a szerver független a hálózati megvalósítástól, mindkettő egy elosztott virtuális gépen belül működik, és az eljáráshívások szabványos interfésszel rendelkeznek.

Paraméterek átadása

Az értékparaméterek átadása nem nehéz. Ebben az esetben az ügyfélcsonk elhelyezi a paraméter értékét a hálózati kérésben, esetleg szabványos konverziók végrehajtásával (például a végpont megváltoztatásával). Sokkal bonyolultabb a helyzet a mutatók átadásával, amikor a paraméter az adatok címe, nem pedig az értéke. Egy cím átadása a kérelemben értelmetlen, mert a távoli eljárás teljesen más címtérben fut. Az RPC-ben használt legegyszerűbb megoldás az, hogy megakadályozzuk, hogy a kliensek értéken kívül más paramétereket adjanak át, bár ez minden bizonnyal komoly korlátozásokat támaszt.

Kötés

Mielőtt egy kliens meghívhatna egy távoli eljárást, hozzá kell rendelni egy távoli rendszerhez, amely rendelkezik a szükséges szerverrel. Így a kötés feladata két részre oszlik:

Távoli gazdagép keresése a kívánt szerverrel

A szükséges szerverfolyamat megkeresése egy adott gazdagépen

Különféle megközelítések használhatók a gazda megtalálására. Lehetséges lehetőség valamilyen központosított címtár létrehozása, amelyben a gazdagépek hirdetik a szervereiket, és ahol a kliens, ha kívánja, kiválaszthatja a neki megfelelő hosztot és az eljárás címét.

Minden RPC-eljárás egyedileg azonosítható egy program- és eljárásszám alapján. A programszám a távoli eljárások egy csoportját határozza meg, amelyek mindegyikének saját száma van. Minden programhoz hozzá van rendelve egy verziószám is, így ha kisebb változtatásokat hajt végre a programon (például eljárást ad hozzá), akkor nem kell a számát módosítani. Jellemzően több funkcionálisan hasonló eljárás kerül megvalósításra egy programmodulban, amely indításkor ezen eljárások szerverévé válik, és amelyet a programszám azonosít.

Így amikor egy ügyfél távoli eljárást szeretne hívni, ismernie kell a kívánt szolgáltatást biztosító programot, verziót és eljárásszámokat.

A kérés elküldéséhez az ügyfélnek ismernie kell a gazdagép hálózati címét és a szükséges eljárásokat biztosító kiszolgálóprogramhoz társított portszámot is. Ez a portmap(IM) démon segítségével történik (egyes rendszereken rpcbind(IM) néven). A démon olyan gazdagépen fut, amely távoli eljárásszolgáltatást biztosít, és jól ismert portszámot használ. A szerverfolyamat inicializálásakor regisztrálja eljárásait és portszámait a portmap(IM)-ben. Most, amikor az ügyfélnek tudnia kell a portszámot egy adott eljárás meghívásához, kérést küld a portmap(IM) szervernek, amely viszont vagy visszaadja a portszámot, vagy közvetlenül továbbítja a kérést a távoli eljáráskiszolgálónak, és válasz az ügyfélnek, amikor végrehajtja. Mindenesetre, ha a szükséges eljárás létezik, a kliens megkapja az eljárás portszámát a portmap(IM) szervertől, és közvetlenül erre a portra küldhet további kéréseket.

Különleges helyzetek kezelése (kivétel)

A kivételek kezelése helyi eljárások hívásakor nem jelent nagy problémát. A UNIX biztosítja a folyamathibák kezelését, mint például a nullával való osztás, az érvénytelen memóriaterülethez való hozzáférés stb. Távoli eljáráshívás esetén megnő a hibahelyzetek valószínűsége. A kiszolgáló- és csonkhibákhoz hozzáadódnak azok a hibák, amelyek például egy hibás hálózati üzenet fogadásához kapcsolódnak.

Például, ha az UDP-t átviteli protokollként használja, az üzenetek egy bizonyos időtúllépés után újraküldésre kerülnek. A kliens hibaüzenetet küld, ha bizonyos számú próbálkozás után nem érkezik válasz a szervertől. TCP protokoll használata esetén hibaüzenetet küld a kliensnek, ha a szerver megszakította a TCP-kapcsolatot.

Hívja a Szemantikát

Egy helyi eljárás meghívása egyértelműen a végrehajtásához vezet, majd a vezérlés visszatér a főprogramhoz. Más a helyzet távoli eljárás hívásakor. Lehetetlen meghatározni, hogy pontosan mikor hajtják végre az eljárást, egyáltalán elvégzik-e, és ha igen, hányszor? Például, ha a kérést a távoli rendszer a kiszolgálóprogram összeomlása után kapja meg, az eljárás egyáltalán nem kerül végrehajtásra. Ha az ügyfél egy bizonyos idő elteltével nem kap választ (időtúllépés), újra elküldi a kérést, akkor olyan helyzet állhat elő, amikor a válasz már továbbításra kerül a hálózaton, és az ismételt kérést a távoli eljárás újra elfogadja feldolgozásra. . Ebben az esetben az eljárást többször is végrehajtják.

Így egy távoli eljárás végrehajtása a következő szemantikával jellemezhető:

- Egyszer és csak egyszer. Ezt a viselkedést (bizonyos esetekben a legkívánatosabb) nehéz megkövetelni az esetleges szerverösszeomlások miatt.

- Maximum idők. Ez azt jelenti, hogy az eljárást vagy egyáltalán nem, vagy csak egyszer hajtották végre. Hasonló állítás tehető, ha normál válasz helyett hibát kap.

- Legalább egyszer. Az eljárást valószínűleg egyszer végezték el, de több is lehetséges. Ilyen helyzetben a normál működéshez a távoli eljárásnak rendelkeznie kell az idempotens tulajdonsággal (az angol idemponentből). Ennek a tulajdonságnak van egy eljárása, amelynek ismételt végrehajtása nem okoz halmozott változásokat. Például egy fájl olvasása idempotens, de szöveg hozzáadása egy fájlhoz nem.

Adatábrázolás

Ha a kliens és a kiszolgáló ugyanazon a rendszeren fut ugyanazon a számítógépen, nincs adat-inkompatibilitási probléma. Mind a kliens, mind a szerver esetében az adatok bináris formában jelennek meg azonos módon. Távoli hívás esetén a dolgot bonyolítja, hogy a kliens és a szerver különböző architektúrájú rendszereken futhatnak, amelyek eltérő adatreprezentációval rendelkeznek (például lebegőpontos érték ábrázolása, végpontosság stb.).

Az RPC rendszer legtöbb implementációja meghatároz néhány szabványos adatreprezentációt, amelyre a kérésekben és válaszokban átadott összes értéket át kell alakítani.

Például a Sun Microsystems RPC adatábrázolási formátuma a következő:

Byte Order – Legnagyobb utolsó

Lebegőpontos értékeket képvisel - IEEE

Karakterábrázolás - ASCII

Funkcionalitásában az RPC rendszer egy köztes helyet foglal el az alkalmazási réteg és a szállítási réteg között. Az OSI-modellnek megfelelően ez a rendelkezés megfelel a prezentációs és a munkamenet rétegeknek. Így az RPC elméletileg független a hálózat megvalósításától, különösen a szállítási réteg hálózati protokolljaitól.

A rendszer szoftveres megvalósításai általában egy vagy két protokollt támogatnak. Például a Sun Microsystems RPC rendszere támogatja az üzenettovábbítást a TCP és UDP protokollok használatával. Az egyik vagy másik protokoll kiválasztása az alkalmazás követelményeitől függ. Az UDP protokoll választása indokolt az alábbi jellemzőkkel rendelkező alkalmazásoknál:

A hívott eljárások idempotensek

Az átadott argumentumok és a visszaadott eredmény mérete kisebb, mint az UDP-csomag mérete - 8 KB.

A szerver több száz klienssel biztosít munkát. Mivel a szerver minden aktív klienssel kénytelen kapcsolatot fenntartani, amikor TCP protokollokkal dolgozik, ez erőforrásainak jelentős részét lefoglalja. Az UDP protokoll kevésbé erőforrásigényes ebből a szempontból.

Másrészt a TCP lehetővé teszi a következő jellemzőkkel rendelkező alkalmazások hatékony működését:

Az alkalmazás megbízható átviteli protokollt igényel

A meghívott eljárások nem-idemponentesek

Az argumentumok vagy a visszatérési eredmény mérete meghaladja a 8 KB-ot

A protokoll megválasztása általában a kliensnél marad, és a rendszer különböző módokon szervezi meg az üzenetek kialakítását és továbbítását. Tehát a TCP protokoll használatakor, amelyhez az átvitt adat egy bájtfolyam, el kell különíteni az üzeneteket egymástól. Ehhez például az RFC1057-ben leírt "RPC: Remote Procedure Call Protocol Specifikation version 2" rekordjelölő protokollt használják, amelyben minden üzenet elejére egy 32 bites egész szám kerül, amely megadja az üzenet méretét. bájtokban.

Más a helyzet a hívás szemantikájával. Például, ha az RPC megbízhatatlan szállítási protokoll (UDP) használatával történik, a rendszer rövid időközönként (időtúllépések) újraküldi az üzenetet. Ha az ügyfélalkalmazás nem kap választ, akkor nyugodtan kijelenthetjük, hogy az eljárást nulla vagy több alkalommal hajtották végre. Ha válasz érkezett, az alkalmazás arra következtethet, hogy az eljárást legalább egyszer elvégezték. A Trusted Transport Protocol (TCP) esetén válasz érkezésekor elmondható, hogy az eljárást egyszer hajtották végre. Ha nem érkezik meg a válasz, nem lehet egyértelműen kijelenteni, hogy az eljárást nem hajtották végre3.

Hogyan működik?

Lényegében maga az RPC rendszer a kliensprogramba és a szerverprogramba van beépítve. A jó hír az, hogy az elosztott alkalmazások fejlesztése során nem kell elmélyedni az RPC protokoll vagy a program üzenetfeldolgozás részleteiben. A rendszer feltételezi a megfelelő fejlesztői környezet meglétét, ami nagyban leegyszerűsíti az alkalmazásszoftverek készítőinek életét. Az RPC egyik kulcsfontosságú pontja, hogy az elosztott alkalmazás fejlesztése az objektum interfész meghatározásával kezdődik – ez a szerver funkcióinak formális leírása, speciális nyelven. Ezen az interfészen alapulva automatikusan létrejönnek a kliens és a szerver csonkok. Ezután már csak a tényleges eljáráskódot kell megírni.

Példaként vegye figyelembe a Sun Microsystems RPC-jét. A rendszer három fő részből áll:

Az Rpcgen(1) egy RPC fordító, amely a távoli eljárási felület leírása alapján kliens és szerver csonkokat állít elő C programok formájában.

Az XDR (eXternal Data Representation) könyvtár, amely a különféle típusú adatok gépfüggetlen formába való konvertálására szolgáló funkciókat tartalmaz, amely lehetővé teszi a heterogén rendszerek közötti információcserét.

A rendszer egészének működését biztosító modulok könyvtára.

Nézzünk egy példát a legegyszerűbb elosztott eseménynaplózó alkalmazásra. Az ügyfél indításkor egy távoli eljárást hív meg, hogy üzenetet írjon a távoli számítógép naplófájljába.

Ehhez legalább három fájlt kell létrehoznia: a log.x távoli eljárási felületek specifikációját (az interfészleíró nyelven), a log.c távoli eljárások tényleges szövegét és a kliens főoldalának szövegét. program fő () - kliens.c (C nyelven).

Az rpcgen(l) fordító három fájlt hoz létre a log.x specifikáció alapján: a kliens és a szerver csonkjainak szövegét C nyelven (log clnt.c és log svc.c), valamint a mindkét csonk által használt log.h leíró fájlt. .

Nézzük tehát a programok forráskódját.

Ez a fájl adja meg a távoli eljárás regisztrációs paramétereit - program, verzió és eljárásszámokat, valamint meghatározza a hívási felületet - a bemeneti argumentumokat és a visszatérési értékeket. Így az RLOG eljárás definiálva van, és argumentumként egy karakterláncot vesz fel (amely a naplóba kerül), és a visszatérési érték alapértelmezés szerint a kért művelet sikerességét vagy sikertelenségét jelzi.

program LOG_PROG(

verzió LOG_VER(

int RLOG(karakterlánc) = 1;

) = 0x31234567;

Az rpcgen(l) fordító létrehoz egy log.h fejlécfájlt, ahol különösen az eljárások vannak meghatározva:

log.h

* Kérjük, ne szerkessze ezt a fájlt.

* Az rpcgen használatával készült.

#ifndef _LOG_H_RPCGEN

#define _LOG_H_RPCGEN

#beleértve

/* Programszám */

#define LOG_PROG ((előjel nélküli hosszú) (0x31234567))

#define LOG_VER ((előjel nélküli hosszú) (1)) /*Verziószám*/

#define RLOG ((előjel nélküli hosszú) (1)) /*Eljárás száma*/

extern int *rlog_l () ;

/* Belső eljárás - nem kell használnunk */ extern int log_prog_l_freeresult();

#endif /* !_LOG_H_RPCGEN */

Nézzük meg közelebbről ezt a fájlt. A fordító az interfészdefiníciós fájlban definiált RLOG nevet rlog_1-re fordítja le, a nagybetűket kisbetűkre cseréli, a program verziószámát pedig aláhúzással fűzi hozzá. A visszatérési típus int-ről int *-ra változott. Ez a szabály – az RPC csak az interfész leírásában deklarált paraméterek címeinek küldését és fogadását teszi lehetővé. Ugyanez a szabály vonatkozik az argumentumként átadott karakterláncra is. Bár a print.h fájl ezt nem jelenti, valójában a sor címe is átadásra kerül argumentumként az rlog_l () függvénynek.

A fejlécfájl mellett az rpcgen(l) fordító kliens csonk és szerver csonkmodulokat is előállít. Lényegében ezeknek a fájloknak a szövege tartalmazza az összes távoli híváskódot.

A szerver csonk az a gazdagép program, amely az ügyféllel (pontosabban a csonkjával) való összes hálózati interakciót kezeli. A művelet végrehajtásához a kiszolgáló csonkja egy helyi függvényhívást hajt végre, melynek szövegét be kell írni:

log.c

#beleértve

#beleértve

#beleértve

#include "log.h"

int *rlog_1(char **arg)

/*A visszatérési értéket statikusként kell megadni*/

statikus int eredmény;

int fd; /*Naplófájl leíró*/

/*0nyissa meg a naplófájlt (hozza létre, ha nem létezik), hibakódot ad vissza, ha nem sikerül eredmény == 1.*/

if ((fd=open("./server .log",

O_CREAT | O_RDWR | O_APPEND))< 0) return (&result);

len = strlen(*arg);

if (write(fd, *arg, strlen(*arg)) != len)

return(&eredmény); /*Az eredmény visszaadása - a cím eredménye*/

A kliens csonk átveszi a távoli eljárásnak átadott argumentumot, elvégzi a szükséges átalakításokat, kérelmet küld a portmap(1M) szervernek, kommunikál a távoli eljáráskiszolgálóval, és végül továbbadja a visszatérési értéket a kliensnek. Az ügyfél számára a távoli eljárás hívása csonk hívására redukálódik, és nem különbözik a szokásos helyi hívástól.

ügyfél.c

#beleértve

#include "log.h"

main(int argc, char *argv)

char *szerver, *mystring, *clnttime;

if (argc != 2) (

fprintf(stderr, "Hívásformátum: %s HostAddress\n",

/* Szerezze be az ügyfélfogadást. Meghibásodás esetén értesítjük Önt a

nem tud kapcsolatot létesíteni a szerverrel*/

if ((c1 = clnt_create (szerver,

LOG_PROG, LOG_VER, "udp")) == NULL) (

clnt_pcreateerror(szerver);

/*Puffer lefoglalása a karakterlánchoz*/

mystring = (char*)malloc(100);

/*Határozza meg az esemény időpontját*/

bintime = idő((idő_t *) NULL);

clnttime = ctime(&bintime);

sprintf(mystring, "%s - Az ügyfél elindult", clnttime);

/*Üzenetet küldünk a naplóhoz - az ügyfél munkakezdésének időpontjáról. Hiba esetén jelezzük a hibát */

if ((eredmény = rlog_l(&mystring, cl)) == NULL) (

fprintf(stderr, "hiba2\n");

clnt_perror(cl, szerver);

/*A távoli számítógép meghibásodása esetén hibajelentés*/

if (*eredmény !=0)

fprintf(stderr, "Hiba a naplóba írva\n");

/*0szabadítsd ki a fogantyút*/

cint rombol(cl);

A log_clnt.c ügyfélcsonk a client.c modullal van lefordítva, hogy egy kliens végrehajtható fájlt hozzon létre.

cc -o rlog client.c log_clnt.c -Insl

A log_svc.c kiszolgálócsonk és a log.c eljárás a kiszolgáló végrehajtható fájljának előállításához van lefordítva.

cc -o logger log_svc.c log.c -Insl

Most néhány host server.nowhere.ru webhelyen el kell indítania a szerverfolyamatot:

Ezt követően, amikor az rlog klienst egy másik gépen elindítják, a szerver hozzáadja a megfelelő bejegyzést a naplófájlhoz.

Az RPC működési sémája ebben az esetben az ábrán látható. 1. A modulok a következőképpen működnek együtt:

1. Amikor egy kiszolgálói folyamat elindul, létrehoz egy UDP-socketet, és minden helyi portot ehhez a sockethez köt. Ezután a szerver meghívja az svc_register(3N) függvénytárat a programszámok és -verziók regisztrálásához. Ehhez a függvény meghívja a portmap(IM) folyamatot, és átadja a szükséges értékeket. A portmap(IM) szerver általában a rendszer inicializálása után indul el, és valamilyen jól ismert porthoz kötődik. Most a portmap(3N) tudja a programunk és verziónk portszámát. A szerver kérés fogadására vár. Vegye figyelembe, hogy az összes leírt műveletet az rpcgen(IM) fordító által létrehozott kiszolgálócsonk hajtja végre.

2. Amikor az rlog program elindul, először meghívja a clnt_create(3N) függvénytárat, megadva a távoli rendszer címét, a program- és verziószámokat, valamint a szállítási protokollt. A függvény kérést küld a távoli rendszerszerver.nowhere.m portmap(IM) szerverének, és lekéri a naplószerver távoli portszámát.

3. Az ügyfél meghívja a kliens csonkjában meghatározott rlog_1() eljárást, és átadja a vezérlést a csonknak. Ez viszont kérést képez (az argumentumok XDR formátumba konvertálásával) UDP-csomag formájában, és elküldi azt a portmap (IM) szervertől kapott távoli portra. Ezután egy ideig vár a válaszra, és ha nem érkezik meg, újra elküldi a kérést. Kedvező körülmények között a kérést a naplózó szerver (szerver csonkmodul) elfogadja. A csonk meghatározza, hogy melyik függvényt hívták meg (az eljárás száma alapján), és meghívja a log.c modul rlog_1() függvényét. Miután visszaadta a vezérlést a csonknak, a csonk az rlog_1 () függvény által visszaadott értéket XDR formátumba konvertálja, és szintén UDP-csomag formájában választ generál. A válasz kézhezvétele után a kliens csonk kivonja a visszaadott értéket, átalakítja és visszaküldi a kliens főprogramjába.


Remote Procedure Call RPC A Remote Procedure Call – RPC koncepciója az ugyanazon a gépen futó programon belüli vezérlés és adatok átadásának jól ismert és jól érthető mechanizmusának kiterjesztése a vezérlés és az adatok hálózaton keresztüli átadására. A távoli eljáráshívási eszközök az elosztott számítástechnika megszervezését hivatottak elősegíteni, az RPC használatának legnagyobb hatékonysága azokban az alkalmazásokban érhető el, amelyekben interaktív kapcsolat van a távoli komponensek között rövid válaszidővel és viszonylag kis mennyiségű adatátvitellel.

Az ilyen alkalmazásokat RPC-orientáltnak nevezzük. A helyi eljárások hívásának sajátossága az Aszimmetria, vagyis az egyik interakcióban részt vevő fél a kezdeményező Szinkronitás, vagyis a hívó eljárás végrehajtása a leállásokban a kérés kibocsátásának pillanatától és csak a hívottból való visszatérés után folytatódik. A távoli hívások megvalósítása sokkal bonyolultabb, mint a helyi eljárásokra irányuló hívások megvalósítása.

Először is, mivel a hívó és a meghívott eljárások különböző gépeken futnak, eltérő címterekkel rendelkeznek, ami problémákat okoz a paraméterek és az eredmények átadásakor, különösen, ha a gépek nem azonosak. Mivel az RPC nem támaszkodhat megosztott memóriára, ez azt jelenti, hogy hogy az RPC paraméterek nem tartalmazhatnak mutatókat nem verem memóriahelyekre, és a paraméterértékeket át kell másolni egyik számítógépről a másikra.

A következő különbség az RPC és a helyi hívás között, hogy szükségszerűen az alapul szolgáló kommunikációs rendszert használja, azonban ezt nem szabad kifejezetten látni sem az eljárások meghatározásában, sem magukban az eljárásokban. A távollét további problémákat vet fel. A hívó program és a hívott helyi eljárás végrehajtása ugyanazon a gépen egyetlen folyamat keretein belül valósul meg, de az RPC megvalósításban legalább két folyamat vesz részt - minden gépben egy.

Abban az esetben, ha valamelyik összeomlik, a következő helyzetek fordulhatnak elő: amikor a hívó eljárás lefagy, a távolról hívott eljárások elárvulnak, ha pedig a távoli eljárások összeomlik, a hívó eljárások nyomorgó szülőkké válnak, akik megvárják a választ a a távoli eljárások eredménytelenül. Ezenkívül számos probléma van a programozási nyelvek heterogenitásával és működési környezetek az egyik programozási nyelvben támogatott adatstruktúrák és eljáráshívási struktúrák nem támogatottak ugyanúgy minden más nyelven.

Ezeket és néhány más problémát megoldja a széles körben elterjedt RPC technológia, amely sok elosztás alapjául szolgál operációs rendszer. Alapműveletek RPC Az RPC működésének megértéséhez először vegyünk egy helyi eljáráshívást egy normál offline gépen. Legyen ez például a count read fd,buf,nbytes rendszerhívás, ahol fd egy egész szám, a buf pedig egy tömb karakter, az nbyte pedig egy egész szám.

A hívás indításához a hívási eljárás fordított sorrendben tolja a paramétereket a verembe. 3.1. ábra. Az olvasás hívása után a visszatérési értéket egy regiszterbe helyezi, áthelyezi a visszatérési címet, és visszaadja a vezérlést a hívó eljárásnak, amely lekéri a paramétereket a veremből, visszaállítja azt. vagy név szerinti hivatkozással , vagy érték szerint érték szerint . A hívott eljárás tekintetében az értékparaméterek inicializálható helyi változók.

A meghívott eljárás megváltoztathatja ezeket, és ez nem befolyásolja ezen változók eredeti értékét a hívó eljárásban. Ha egy változóra mutató mutatót adunk át a meghívott eljárásnak, akkor ennek a változónak az értékének megváltoztatása a meghívott eljárással azt jelenti, hogy ennek a változónak az értékét is megváltoztatjuk a hívó eljáráshoz, ami az RPC esetében nagyon fontos. Van egy másik paraméterátadási mechanizmus is, amelyet a C nyelv nem használ. Ezt hívják másolásonkénti visszaállításnak, amely megköveteli, hogy a hívó program a változókat értékként a verembe másolja, majd a hívás után visszamásolja. a hívó eljárás eredeti értékei fölé került.

A használni kívánt paraméterátadási mechanizmus kiválasztása a nyelvi tervezőkön múlik. Néha ez attól függ, hogy milyen típusú adatokat továbbítunk.C-ben például az egész számokat és más skaláris adatokat mindig érték szerint, míg a tömböket mindig hivatkozással.

Rizs. 3.1. a Verem az olvasási hívás előtt b Verem az eljárás végrehajtása közben a verembe a hívó programhoz való visszatérés után Az RPC mögött az az elgondolás, hogy a távoli eljáráshívás a lehető legjobban helyi eljáráshívásnak tűnjön. Más szóval, az RPC átláthatóvá tételéhez a hívó eljárásnak nem kell tudnia, hogy a hívott eljárás egy másik gépen van, és fordítva: az RPC a következő módon éri el az átláthatóságot.

Ha a meghívott eljárás valóban egy távoli eljárás, akkor az eljárás egy másik verziója, az úgynevezett kliens csonk kerül a könyvtárba a helyi eljárás helyett. Az eredeti eljáráshoz hasonlóan a csonkot a 3.1. ábrán látható hívási sorrend használatával hívják meg, és a kernel elérésekor megszakítás történik. Csak az eredeti eljárástól eltérően nem rak be paramétereket a regiszterekbe és nem kér adatokat a kerneltől, hanem üzenetet küld a távoli gép kernelének. RPC végrehajtási szakaszok A szoftverkomponensek interakcióját távoli eljáráshívás végrehajtásakor a 3.2. ábra szemlélteti. Miután az ügyfélprogram meghívta az ügyfélcsonkot, az első feladata a puffer feltöltése az általa küldött üzenettel.

Egyes rendszereken az ügyfélcsonk egyetlen fix hosszúságú pufferrel rendelkezik, amely minden új kérés beérkezésekor az elejétől fogva feltöltődik. Más rendszereken az üzenetpuffer az egyes üzenetmezők puffereinek készlete, amelyek közül néhány már megtelt.

Ez a módszer különösen akkor megfelelő, ha a csomag formátuma nagyszámú mezőből áll, de sok mező értéke nem változik hívásról hívásra. Ezután a paramétereket a megfelelő formátumra kell konvertálni és be kell illeszteni az üzenetpufferbe, ekkor az üzenet készen áll a továbbításra, így a rendszermag megszakítása történik. Rizs. 3.2. Távoli eljáráshívás Amikor a kernel megkapja a vezérlést, kontextust vált, processzorregisztereket és memórialeképezési oldalleírókat ment el, beállít új kártya a kernel módhoz használandó memória. Mivel a kernel és a felhasználói kontextus különbözik, a kernelnek pontosan be kell másolnia az üzenetet a saját címterébe, hogy el tudja érni, emlékezzen a célcímre és esetleg más fejlécmezőkre, és át kell adnia a hálózati interfésznek.

Ezzel befejeződik a munka a kliens oldalon.

Az átviteli időzítő elindul, és a kernel végrehajthat egy körkérdést a válaszért, vagy átadhatja a vezérlést az ütemezőnek, amely más folyamatot választ a futtatásra. Az első esetben a lekérdezés végrehajtása felgyorsul, de nincs többprogramozás. A szerver oldalon a bejövő biteket a fogadó hardver egy beépített pufferbe vagy RAM.Ha minden információ beérkezett, megszakítás jön létre.

A megszakításkezelő ellenőrzi, hogy a csomagadatok helyesek-e, és meghatározza, hogy melyik csonknak kell továbbítania azokat.Ha nem várja a csomagot, a megszakításkezelőnek vagy pufferelnie kell, vagy teljesen el kell dobnia. Ha van egy várakozó csonk, akkor az üzenet átmásolódik rá. Végül egy kontextusváltás történik, amely visszaállítja a regisztereket és a memórialeképezést azokra az értékekre, amelyek a csonk fogadásakor voltak.

Most a kiszolgáló csonkja elkezd működni. Kicsomagolja a paramétereket, és megfelelően a verembe tolja. Amikor minden készen áll, a hívás megtörténik a szerver felé. Az eljárás befejezése után a szerver elküldi az eredményeket a kliensnek, ehhez az összes fent leírt lépést végrehajtja, csak fordított sorrendben. A 3.3. ábra mutatja az egyes RPC-hívásokhoz végrehajtandó parancsok sorrendjét, a 3.4. ábra pedig azt, hogy a teljes RPC-végrehajtási idő mekkora hányadát tölti a leírt 14 szakasz mindegyikében.

A kutatást többprocesszoron végezték munkaállomás DEC Firefly, és bár az öt processzor jelenléte szükségszerűen befolyásolta a mérési eredményeket, az ábrán látható hisztogram általános képet ad az RPC végrehajtási folyamatáról. Rizs. 3.3. Az RPC eljárás szakaszai Fig. 3.4. Az idő eloszlása ​​az RPC végrehajtás 14 szakasza között 1. Hívja meg a csonkot 2. Készítse elő a puffert 3. Csomagolja be a paramétereket 4. Töltse ki a fejléc mezőt 5. Számítsa ki az üzenetben szereplő ellenőrző összeget 6. Megszakítás a kernelhez 7. Állítsa sorba a csomagot végrehajtáshoz 8. Üzenet küldése a QBUS buszon lévő vezérlőnek 9. Ethernet átviteli idő 10. csomag fogadása a vezérlőtől 11. megszakítási rutin 12. ellenőrző összeg kiszámítása 13. kontextus váltás felhasználói területre 14. kiszolgáló csonk végrehajtása

A probléma megoldásának egyik módja a kiszolgáló hálózati címének közvetlen használata az ügyfélprogramban.

Ennek a megközelítésnek az a hátránya, hogy rendkívül rugalmatlan egy szerver áthelyezésekor, vagy a szerverek számának növelésekor, vagy a felület megváltoztatásakor ezekben és sok más esetben újra kell fordítani minden olyan programot, ami keményen használt. A fenti problémák elkerülése érdekében egyes elosztott rendszerek dinamikus linkelést használnak.

A dinamikus linkelés kiindulópontja a szerverspecifikáció formális meghatározása. A specifikáció tartalmazza a fájlszerver nevét, verziószámát és a szerver által az ügyfelek számára biztosított szolgáltatási eljárások listáját (3.5. ábra). Minden eljáráshoz meg van adva a paramétereinek leírása, jelezve, hogy ez a paraméter a szerverhez viszonyítva bemeneti vagy kimeneti.Egyes paraméterek bemeneti és kimeneti is lehetnek - például módosul néhány tömb, amelyet a kliens küld a szervernek ott, majd a művelet visszakerül a kliensbe.másolás visszaállítás . Rizs. 3.5. RPC-kiszolgálóspecifikáció A formális kiszolgálóspecifikáció a kliens- és a kiszolgálócsonkokat is létrehozó csonkgenerátor program bemeneteként szolgál.

Ezután bekerülnek a megfelelő könyvtárukba. Amikor egy felhasználói kliensprogram meghív egy, a kiszolgáló specifikációjában meghatározott eljárást, a megfelelő csonk eljárás a program binárishoz van társítva.

Hasonlóképpen, amikor egy kiszolgálót lefordítanak, a szerver csonkokat társítanak hozzá. Amikor a szerver elindul, a legelső lépés a kiszolgálófelület átadása speciális program, úgynevezett binder ohm. Ez a szerverregisztrációs folyamatként ismert folyamat során a szerver megadja a nevét, a verziószámát, az egyedi azonosítót és a szerver helyének azonosítóját. A kezelő rendszerfüggetlen, lehet IP, Ethernet, X.500 vagy bármi más. cím.

Ezenkívül egyéb információkat is tartalmazhat, például a hitelesítéssel kapcsolatban. Amikor a kliens először hívja meg az egyik távoli eljárást, például olvassa el, a kliens csonkja azt látja, hogy még nem csatlakozik a szerverhez, és üzenetet küld a binder programnak azzal a kéréssel, hogy importálja a kiszolgáló felületét. Ha létezik ilyen szerver, akkor a binder átadja a leírót és az egyedi azonosítót a kliens csonkjához.

A kliens csonk, amikor egy kérést tartalmazó üzenetet küld, egy leírót használ címként. Az üzenet paramétereket és egy egyedi azonosítót tartalmaz, amelyet a kiszolgálómotor arra használ, hogy a bejövő üzenetet a megfelelő kiszolgálóra irányítsa, ha több ilyen van a gépen. Az interfészek importálásának és exportálásának ez a módja rendkívül rugalmas, például előfordulhat, hogy több szerver is támogatja ugyanazt a felületet, és a kliensek véletlenszerűen vannak elosztva a szerverek között.

Ennek a módszernek a részeként lehetővé válik a szerverek időszakos lekérdezése, teljesítményük elemzése és hiba esetén automatikus kikapcsolás, ami növeli a rendszer általános hibatűrését. Ez a módszer támogathatja a kliens hitelesítést is. Például egy szerver megállapíthatja, hogy csak egy adott listán szereplő kliensek használhatják, azonban a dinamikus összerendelésnek vannak hátrányai, például az exportáló és importáló felületek többletterhelése.

Ezeknek a költségeknek a nagysága jelentős lehet, mivel számos ügyfélfolyamat létezik egy kis idő, és a folyamat minden indításakor újra el kell végezni az interfész importálási eljárását. Ráadásul a nagy elosztott rendszerekben a binder program szűk keresztmetszetgé válhat, és több azonos célú program létrehozása is növeli a folyamatok létrehozásának és szinkronizálásának többletköltségét RPC szemantika meghibásodás esetén Ideális esetben az RPC-nek megfelelően kell működnie kudarcok.

Tekintsük a következő hibaosztályokat 1. Az ügyfél nem tudja meghatározni a kiszolgáló helyét, például ha a kívánt szerver meghibásodik, vagy mert a kliensprogramot régen fordították le és használták régi verzió szerver interfész. Ebben az esetben az ügyfél kérésére egy hibakódot tartalmazó üzenet érkezik. 2. A klienstől a szerver felé küldött kérés elveszett.A legegyszerűbb megoldás az átadás pontos idő ismételje meg a kérést. 3. Elveszett válaszüzenet a szervertől a kliens felé.

Ez a lehetőség bonyolultabb, mint az előző, mivel egyes eljárások nem idempotensek. Idempotens eljárásnak nevezzük azt az eljárást, amelynek végrehajtási kérése többször megismételhető az eredmény megváltoztatása nélkül. Ilyen eljárásra példaként szolgálhat egy fájl olvasása, azonban egy bizonyos összeg bankszámláról történő felvétele nem idempotens, és ha a válasz elveszik, egy ismételt kérés jelentősen megváltoztathatja az ügyfél számlájának állapotát.

Az egyik lehetséges megoldás az összes eljárás idempotenssé tétele. A gyakorlatban azonban ez nem mindig lehetséges, ezért egy másik módszer is használható - az összes kérés sorszámozása az ügyfélmag által. A szervermag megjegyzi az egyes kliensek legfrissebb kérésének számát, és minden kérés beérkezésekor elemzi, hogy ez a kérés elsődleges vagy ismétlődő. 4. A szerver lefagyott a kérés fogadása után Itt is fontos az idempotencia tulajdonsága, de sajnos a kérésszámozási megközelítés nem alkalmazható.

Ebben az esetben az számít, hogy a hiba mikor következett be – a művelet előtt vagy után. De a kliens mag nem ismeri fel ezeket a helyzeteket, csak azt tudja, hogy a válasz lejárt. Ennek a problémának három módja van. Várjon, amíg a kiszolgáló újraindul, és próbálja meg újra a műveletet.Ez a megközelítés biztosítja, hogy az RPC legalább egyszer, de esetleg többször is befejeződjön. A hibát azonnal jelentse az alkalmazásnak.

Ez a megközelítés biztosítja, hogy az RPC-t legfeljebb egyszer hajtsák végre. A harmadik megközelítés nem garantál semmit. Ha a szerver meghibásodik, az ügyfél nem kap támogatást. Az RPC vagy egyáltalán nem, vagy többször is végrehajtható. Mindenesetre ez a módszer nagyon könnyen megvalósítható. Ezen megközelítések egyike sem túl vonzó, és az ideális megoldás, amely pontosan egy RPC-végrehajtást garantálna, alapvető okok miatt általában nem valósítható meg.

Legyen például egy távoli művelet valamilyen szöveg nyomtatása, amely magában foglalja a nyomtatópuffer betöltését és egy bit beállítását valamilyen nyomtatóvezérlő regiszterben, ami a nyomtató elindulását idézi elő. A szerver összeomlás történhet mikroszekundum előtt vagy után vezérlőbit be van állítva. A meghibásodás pillanata teljes mértékben meghatározza a helyreállítási eljárást, de az ügyfél nem tudhatja meg a meghibásodás pillanatát.

Röviden, a szerver összeomlásának lehetősége gyökeresen megváltoztatja az RPC természetét, és egyértelműen tükrözi a különbséget a központosított és elosztott rendszer. Az első esetben a szerver összeomlása kliens összeomlásához vezet, és a helyreállítás lehetetlen. A második esetben a rendszer helyreállítására irányuló műveletek lehetségesek és szükségesek is. 1. Az ügyfél összeomlott egy kérés elküldése után. Ebben az esetben olyan eredményeket végeznek, amelyekre senki sem számít.Az ilyen számításokat árváknak nevezzük. Az árvák jelenléte különféle problémákat okozhat: CPU-idő túllépése, erőforrás blokkolása, az aktuális kérésre adott válasz helyettesítése a kliensgép által a rendszer újraindítása előtt kiadott kéréssel.

Hogyan bánjunk az árvákkal? Vegye figyelembe a 4 lehetséges megoldások. Megsemmisítés. Mielőtt egy kliens csonk RPC-üzenetet küldene, naplóbejegyzést készít a következő lépésről.

Az összeomlás után a rendszer újraindul, a napló elemzése megtörténik, és az árvák megszűnnek. Ennek a megközelítésnek a hátrányai egyrészt az egyes RPC-k lemezre írásával járó megnövekedett költségek, másrészt az első generációs árvák által kibocsátott RPC-k által generált második generációs árvák megjelenése miatti lehetséges hatástalanság. Reinkarnáció Ebben az esetben minden probléma megoldódik lemezírás nélkül. A módszer abból áll, hogy az időt egymást követő számozott periódusokra osztják. Amikor a kliens újraindul, üzenetet küld az összes gépnek egy új időszak kezdetéről.

Az üzenet kézhezvételekor minden távoli számítás leáll. Természetesen, ha a hálózat szegmentált, akkor néhány árva életben maradhat. A lágy reinkarnáció hasonló az előző esethez, azzal a különbséggel, hogy nem minden távoli számítás található és semmisül meg, hanem csak az újraindító kliens számításai. Határidő Minden kérésnek van egy szabványos időtartama (T), amelyen belül teljesíteni kell.

Ha a kérés nem fejeződik be a megadott időn belül, akkor további kvantum kerül kiosztásra. Bár ez további munkát igényel, ha egy kliens összeomlása után a szerver egy T intervallumot vár, mielőtt újraindítaná a klienst, akkor az összes árva megsemmisül. A gyakorlatban egyik megközelítés sem kívánatos; Tegyük fel például, hogy egy árva egy vagy több adatbázisfájlt zárolt.

Ha egy árva hirtelen megsemmisül, akkor ezek a zárak megmaradnak, ráadásul a megsemmisült árvák állva maradhatnak különböző rendszersorokban, a jövőben új folyamatok végrehajtását idézhetik elő, stb.

Mit csinálunk a kapott anyaggal:

Ha ez az anyag hasznosnak bizonyult az Ön számára, elmentheti az oldalára a közösségi hálózatokon:

4. előadás

4.1 A távoli eljáráshívás fogalma

A távoli eljárások hívásának ötlete (Távoli eljáráshívás – RPC) Az ugyanazon a gépen futó programon belüli vezérlés és adatok átvitelének jól ismert és jól érthető mechanizmusának kiterjesztése a vezérlés és az adatok hálózaton keresztüli átvitelére. A távoli eljáráshívási eszközöket az elosztott számítástechnika szervezésének megkönnyítésére tervezték. Az RPC leghatékonyabb felhasználása azokban az alkalmazásokban érhető el, amelyekben interaktív kommunikáció zajlik a távoli komponensek között, kis válaszidővel és viszonylag kis mennyiségű adatátvitellel. Az ilyen alkalmazásokat RPC-orientáltnak nevezzük.

A lokális eljárások hívásának jellemző vonásai: aszimmetria, vagyis az egyik interakciós fél a kezdeményező; szinkron, vagyis a hívó eljárás végrehajtása a leállásokban a kérés kibocsátásának pillanatától és csak a hívott eljárásból való visszatérés után folytatódik.

A távoli hívások megvalósítása sokkal bonyolultabb, mint a helyi eljáráshívások megvalósítása. Először is, mivel a hívó és meghívott eljárások különböző gépeken futnak, eltérő címterekkel rendelkeznek, és ez problémákat okoz a paraméterek és az eredmények átadásakor, különösen, ha a gépek nem azonosak. Mivel az RPC nem támaszkodhat megosztott memóriára, ez azt jelenti, hogy az RPC-paraméterek nem tartalmazhatnak mutatókat nem verem memóriahelyekre, és a paraméterértékeket át kell másolni egyik számítógépről a másikra. A következő különbség az RPC és a helyi hívás között, hogy szükségszerűen az alapul szolgáló kommunikációs rendszert használja, azonban ezt nem szabad kifejezetten látni sem az eljárások meghatározásában, sem magukban az eljárásokban. A távollét további problémákat vet fel. A hívó program és a hívott helyi eljárás végrehajtása ugyanazon a gépen egyetlen folyamaton belül valósul meg. De legalább két folyamat vesz részt az RPC megvalósításában, mindegyik gépen egy. Ha valamelyik összeomlik, a következő helyzetek adódhatnak: ha a hívó eljárás összeomlik, a távolról hívott eljárások elárvulnak, ha pedig a távoli eljárások összeomlanak, akkor a hívó eljárások "rászoruló szülőkké" válnak, akik válaszra várnak a távoli eljárások eredménytelenül.

Ezen túlmenően a programozási nyelvek és a működési környezetek heterogenitása számos problémával jár: az egyik programozási nyelvben támogatott adatstruktúrák és eljáráshívási struktúrák nem támogatottak ugyanúgy minden más nyelven.


Ezeket és néhány más problémát megoldja a széles körben elterjedt RPC technológia, amely számos elosztott operációs rendszer mögött áll.

Alapvető RPC műveletek

Az RPC működésének megértéséhez először fontolja meg egy helyi eljáráshívás kezdeményezését egy normál, offline üzemmódban futó gépen. Legyen ez például egy rendszerhívás

count=read(fd,buf,nbytes);

ahol fd egész szám;

A buf karakterek tömbje;

Az nbyte egy egész szám.

A hívás indításához a hívási eljárás fordított sorrendben tolja a paramétereket a verembe. Az olvasási hívás befejezése után a visszatérési értéket egy regiszterbe helyezi, áthelyezi a visszatérési címet, és visszaadja a vezérlést a hívó eljáráshoz, amely lekéri a paramétereket a veremből, és visszaállítja azt. Vegye figyelembe, hogy a C-ben a paraméterek vagy hivatkozással (névvel) vagy értékkel (érték szerint) hívhatók meg. A hívott eljárás tekintetében az értékparaméterek inicializálható helyi változók. A meghívott eljárás megváltoztathatja ezeket, és ez nem befolyásolja ezen változók eredeti értékét a hívó eljárásban.

Ha egy változóra mutató mutatót adunk át a meghívott eljárásnak, akkor ennek a változónak a meghívott eljárás általi megváltoztatása maga után vonja a változó értékének megváltoztatását a hívó eljáráshoz. Ez a tény nagyon fontos az RPC számára.

A paraméterek átadására van egy másik, a C nyelvben nem használt mechanizmus is. Ezt call-by-copy/restore-nak hívják, és abból áll, hogy a hívó programnak be kell másolnia a változókat a verembe értékként, majd átmásolni. vissza a hívás után a hívási eljárás eredeti értékein.

A használni kívánt paraméterátadási mechanizmus kiválasztása a nyelvi tervezőkön múlik. Néha ez az átvitt adatok típusától függ. C-ben például az egész számokat és más skaláris adatokat mindig érték, a tömböket pedig mindig hivatkozással adjuk át.

Az RPC mögött az az ötlet, hogy a távoli eljáráshívás ugyanúgy nézzen ki, mint egy helyi eljáráshívás, ha lehetséges. Más szóval, tegye átláthatóvá az RPC-t: a hívó eljárásnak nem kell tudnia, hogy a hívott eljárás egy másik gépen van, és fordítva.

Az RPC a következő módon éri el az átláthatóságot. Ha a hívott eljárás valóban távoli, az eljárás egy másik verziója, az úgynevezett kliens csonk kerül a könyvtárba a helyi eljárás helyett. Az eredeti eljáráshoz hasonlóan a csonkot a hívási sorrend segítségével hívják meg, és a kernel elérésekor megszakítás történik. Csak az eredeti eljárástól eltérően nem rak be paramétereket a regiszterekbe és nem kér adatokat a kerneltől, hanem üzenetet küld a távoli gép kernelének.

RPC végrehajtási lépések

A szoftverkomponensek interakcióját távoli eljáráshívás végrehajtásakor a 2. ábra szemlélteti.

2. ábra Távoli eljáráshívás

Miután az ügyfélprogram meghívta az ügyfélcsonkot, az első feladata a puffer feltöltése az általa küldött üzenettel. Egyes rendszereken az ügyfélcsonk egyetlen fix hosszúságú pufferrel rendelkezik, amely minden új kérés beérkezésekor az elejétől fogva feltöltődik. Más rendszereken az üzenetpuffer az egyes üzenetmezők puffereinek készlete, amelyek közül néhány már megtelt. Ez a módszer különösen akkor megfelelő, ha a csomag formátuma nagyszámú mezőből áll, de sok mező értéke nem változik hívásról hívásra.

A paramétereket ezután a megfelelő formátumba kell konvertálni, és be kell illeszteni az üzenetpufferbe. Ezen a ponton az üzenet készen áll az átvitelre, így a rendszermag megszakítása kerül végrehajtásra.

Amikor a kernel átveszi az irányítást, kontextust vált, elmenti a processzorregisztereket és a memórialeírásokat (oldalleírókat), új memóriatérképet állít be a kernel módú működéshez. Mivel a kernel és a felhasználói kontextus különbözik, a kernelnek pontosan be kell másolnia az üzenetet a saját címterébe, hogy el tudja érni, emlékezzen a célcímre (és esetleg más fejlécmezőkre), és át kell adnia a hálózatnak. felület. Ezzel befejeződik a munka a kliens oldalon. Az átviteli időzítő elindul, és a kernel végrehajthat egy körkérdést a válaszért, vagy átadhatja a vezérlést az ütemezőnek, amely más folyamatot választ a futtatásra. Az első esetben a lekérdezés végrehajtása felgyorsul, de nincs többprogramozás.

A szerver oldalon a bejövő biteket a fogadó hardver egy beépített pufferbe vagy a RAM-ba helyezi el. Amikor minden információ megérkezett, megszakítás jön létre. A megszakításkezelő ellenőrzi a csomagadatok érvényességét, és meghatározza, hogy melyik csonkot adja át. Ha egyik csonk sem várja ezt a csomagot, a kezelőnek vagy pufferelnie kell, vagy teljesen el kell dobnia. Ha van egy várakozó csonk, akkor az üzenet átmásolódik rá. Végül egy kontextusváltás történik, amely visszaállítja a regisztereket és a memórialeképezést azokra az értékekre, amelyek a csonk fogadásakor voltak.

Most a kiszolgáló csonkja elkezd működni. Kicsomagolja a paramétereket, és megfelelően a verembe tolja. Amikor minden készen áll, a hívás megtörténik a szerver felé. Az eljárás végrehajtása után a szerver elküldi az eredményeket a kliensnek. Ehhez az összes fent leírt lépést végrehajtják, csak fordított sorrendben.

A 3. ábra az egyes RPC-hívásokhoz végrehajtandó parancsok sorrendjét mutatja.

3. ábra. Az RPC eljárás lépései

Ha hibát észlel, jelöljön ki egy szövegrészt, és nyomja meg a Ctrl + Enter billentyűket
OSSZA MEG: