Fjärrproceduranrop. Remote Procedure Call (RPC)


Syftet med denna artikel är att diskutera terminologin. Artikeln handlar inte om hur och varför, utan enbart om användningen av terminologi. Artikeln återspeglar författarens åsikt och gör inte anspråk på att vara vetenskaplig.

Introduktion

Om du arbetar inom programmering distribuerade system eller in systemintegration, då är det mesta av det som presenteras här inte nytt för dig.

Problemet uppstår när människor som använder olika teknologier möts och när dessa personer startar tekniska samtal. I det här fallet finns det ofta ett ömsesidigt missförstånd på grund av terminologi. Här ska jag försöka föra samman terminologier som används i olika sammanhang.

Terminologi

Det finns ingen tydlig terminologi och klassificering inom detta område. Terminologin som används nedan är en återspegling av författarens modell, det vill säga den är strikt subjektiv. All kritik och alla diskussioner är välkomna.

Jag har delat in terminologin i tre områden: RPC (Remote Procedure Call), Messaging och REST. Dessa områden har historiska rötter.

RPC

RPC teknologier är de äldsta teknologierna. De smartaste representanterna för RPC är - CORBA Och DCOM.

På den tiden var man främst tvungen att länka ihop system i snabba och relativt pålitliga lokala nätverk. Huvudtanken bakom RPC var att göra anropande fjärrsystem ungefär som anropsfunktioner i ett program. All fjärranropsmekanik gömdes för programmeraren. De försökte åtminstone dölja det. Programmerare var i många fall tvungna att arbeta på en djupare nivå, där termerna marshaling dök upp ( rangering) Och unmarshalling(hur är det på ryska?), vilket i huvudsak innebar serialisering. Normala funktionsanrop inom processer hanterades på den som ringde in ombud, och på sidan av systemet som utför funktionen, i Avsändare. Helst hanterade varken anropssystemet eller bearbetningssystemet krångligheterna med att överföra data mellan system. Alla dessa subtiliteter var koncentrerade i Proxy - Dispatcher-paketet, vars kod genererades automatiskt.

Så du kommer inte att märka, du ska inte märka, någon skillnad mellan att anropa en lokal funktion och att anropa en fjärrfunktion.
Nu finns det en slags RPC-renässans, vars mest framstående representanter är: Google ProtoBuf, Thrift, Avro.

Meddelanden

Med tiden visade det sig att ett försök att skydda programmeraren från det faktum att den anropade funktionen fortfarande skiljer sig från den lokala inte ledde till det önskade resultatet. Implementeringsdetaljerna och grundläggande skillnader mellan distribuerade system var för stora för att kunna lösas med automatiskt genererad proxykod. Efter hand kom förståelsen att det faktum att systemen är sammankopplade av en opålitlig, långsam miljö med låg hastighet uttryckligen borde återspeglas i programkoden.

Teknologier har dykt upp webbservice. Vi började prata ABC: Adress, Bindande, Kontrakt. Det är inte helt klart varför kontrakt dök upp, som i huvudsak är kuvert (kuvert) för inmatningsargument. Kontrakt komplicerar ofta hela modellen snarare än att förenkla den. Men bry dig inte.

Nu har programmeraren uttryckligen skapat service(Service) eller klient(klient) som anropar tjänsten. Tjänsten var en uppsättning operationer (drift), som var och en vid ingången tog förfrågan(Begäran) och utfärdas svar(Svar). klient uttryckligen skickas(helgon) begäran, tjänsten uttryckligen tagit emot ( motta) och svarade (Skickat), skickade svaret. Klienten fick (ta emot) svaret och på det avslutades samtalet.

Precis som i RPC, fungerade Proxy och Dispatcher någonstans här. Och som tidigare genererades deras kod automatiskt och programmeraren behövde inte förstå den. Såvida inte klienten uttryckligen använde klasser från proxy.

Förfrågningar och svar konverteras uttryckligen till trådformatet. Oftast är det en uppsättning byte. Förvandlingen kallas Serialisering Och Deserialisering och gömmer sig ibland i proxykoden.
Kulminationen av meddelanden manifesterade sig i framväxten av ett paradigm ESB (Enterprise Service Bus). Ingen kan riktigt formulera vad det är, men alla är överens om att data om ESB:en rör sig i form av meddelanden.

RESTEN

I en ständig kamp med kodens komplexitet tog programmerare nästa steg och skapade RESTEN.

Den grundläggande principen för REST är att funktionsoperationer är kraftigt begränsade och lämnade endast en uppsättning operationer. CRUD: Skapa - Läs - Uppdatera - Ta bort. I denna modell tillämpas alltid alla operationer på vissa data. Operationerna som finns tillgängliga i CRUD är tillräckliga för de flesta applikationer. Eftersom REST-teknologier i de flesta fall involverar användningen av HTTP-protokollet, återspeglades CRUD-kommandona i kommandona http (posta - Skaffa sig - Sätta - Radera) . Det hävdas ständigt att REST inte nödvändigtvis är kopplat till HTTP. Men i praktiken används reflektionen av operationssignaturer på syntaxen för HTTP-kommandon i stor utsträckning. Till exempel ett funktionsanrop

EntityAddress ReadEntityAddress(sträng param1, sträng param2)

Uttryckt så här:

GET: entityAddress?param1=värde1¶m2=värde2

Slutsats

Innan du börjar en diskussion om distribuerade system eller integration, definiera lite terminologi. Om Proxy alltid betyder samma sak i olika sammanhang, så kommer till exempel begäran att betyda lite i termer av RPC, och rangordning kommer att orsaka förvirring när man diskuterar REST-teknologier.

Fjärrproceduranrop(eller Ringer fjärrprocedurer) (från engelska. Remote Procedure Call (RPC)) - en klass av teknologier som tillåter datorprogram att anropa funktioner eller procedurer i ett annat adressutrymme (vanligtvis på fjärrdatorer). Vanligtvis inkluderar en implementering av RPC-teknik två komponenter: ett nätverksprotokoll för klient-serverkommunikation och ett objekt (eller struktur, för icke-objektiv RPC) serialiseringsspråk. Olika implementeringar av RPC har väldigt olika arkitekturer och skiljer sig i sina möjligheter: vissa implementerar SOA-arkitekturen, andra CORBA eller DCOM. På transportlagret använder RPC:er huvudsakligen TCP- och UDP-protokoll, dock är vissa byggda ovanpå HTTP (vilket bryter mot ISO/OSI-arkitekturen, eftersom HTTP inte ursprungligen är ett transportprotokoll).

Genomföranden

Det finns många tekniker som tillhandahåller RPC:

  • Sun RPC (binärt protokoll baserat på TCP och UDP och XDR) RFC-1831 alias ONC RPC RFC-1833
  • .Net Remoting (binärt protokoll baserat på TCP, UDP, HTTP)
  • SOAP - Simple Object Access Protocol (textprotokoll baserat på HTTP) se specifikation: RFC-4227
  • XML RPC (HTTP-baserat textprotokoll) se specifikation: RFC-3529
  • Java RMI - Java Remote Method Invocation - se spec: http://java.sun.com/j2se/1.5.0/docs/guide/rmi/index.html
  • JSON-RPC JavaScript Object Notation Remote Procedure Calls (HTTP-baserat textprotokoll) se specifikation: RFC-4627
  • DCE / RPC - Distributed Computing Environment / Remote Procedure Calls (binärt protokoll baserat på olika transportprotokoll, inklusive TCP / IP och Named Pipes från SMB / CIFS-protokollet)
  • DCOM - Distributed Component Object Model känd som MSRPC Microsoft Remote Procedure Call eller "Network OLE"

Princip

Tanken bakom Remote Procedure Call (RPC) är att utöka den välkända och välkända mekanismen för att överföra kontroll och data inom ett program som körs på samma maskin till att överföra kontroll och data över ett nätverk. Verktyg för fjärranrop är utformade för att underlätta organisationen av distribuerad datoranvändning och skapandet av distribuerade klient-serverinformationssystem. Den mest effektiva användningen av RPC uppnås i de applikationer där det finns en interaktiv kommunikation mellan fjärrkomponenter med en kort svarstid och en relativt liten mängd överförd data. Sådana applikationer kallas RPC-orienterade.

Implementeringen av fjärrsamtal är mycket mer komplicerad än implementeringen av lokala procedursamtal. Vi kan identifiera följande problem och uppgifter som behöver lösas när vi implementerar RPC:

  • Eftersom anrops- och anropsprocedurerna körs på olika maskiner har de olika adressutrymmen, och detta skapar problem när parametrar och resultat skickas, speciellt om maskinerna kör olika operativsystem eller har olika arkitekturer (till exempel little endian eller little endian är används). ). Eftersom RPC inte kan förlita sig på delat minne, betyder detta att RPC-parametrar inte får innehålla pekare till icke-stackminnesplatser och att parametervärden måste kopieras från en dator till en annan. För att kopiera parametrarna för proceduren och resultatet av exekvering via nätverket serialiseras de.
  • Till skillnad från ett lokalt samtal använder ett fjärranrop nödvändigtvis nätverksarkitekturens transportlager (till exempel TCP), men detta förblir dolt för utvecklaren.
  • Exekveringen av det anropande programmet och den anropade lokala proceduren på samma maskin implementeras inom en enda process. Men det finns minst två processer involverade i RPC-implementering, en på varje maskin. Om en av dem kraschar kan följande situationer uppstå: om anropsproceduren kraschar, kommer de fjärranropade procedurerna att bli "föräldralösa", och om fjärrprocedurerna kraschar, kommer anropsprocedurerna att bli "utlösa föräldrar", vilket kommer att vänta på en svar från fjärrprocedurerna till ingen nytta.
  • Det finns ett antal problem förknippade med heterogeniteten hos programmeringsspråk och driftsmiljöer: datastrukturer och strukturer för proceduranrop som stöds i ett programmeringsspråk stöds inte på samma sätt på alla andra språk. Det finns alltså ett kompatibilitetsproblem som ännu inte har lösts vare sig genom införandet av en allmänt accepterad standard eller genom implementeringen av flera konkurrerande standarder på alla arkitekturer och på alla språk.

Delsystem

  • Transportdelsystem

Hantering av utgående och inkommande anslutningar. - Stöd för konceptet "meddelandegräns" för transportprotokoll som inte direkt stöder det (TCP). - stöd för garanterad leverans för transportprotokoll som inte direkt stöder det (UDP).

  • Trådpool (endast för uppringd part). Tillhandahåller en exekveringskontext för kod som anropas över nätverket.
  • Marshalling (även kallad "serialisering"). Packa anropsparametrar i en byteström på ett standardsätt som inte beror på arkitekturen (särskilt på ordningen av bytes i ett ord). I synnerhet kan det påverka arrayer, strängar och strukturer som pekas på av pekparametrar.
  • Paketkryptering och digital signatur.
  • Autentisering och auktorisering. Överföringen över nätverket av information som identifierar personen som ringer.

I vissa implementeringar av RPC (.NET Remoting) är delsystemsgränser öppna polymorfa gränssnitt, och det är möjligt att skriva en egen implementering av nästan alla listade delsystem. I andra implementeringar (DCE RPC på Windows) är detta inte fallet.

se även

Remote Procedure Call (RPC) Begreppet Remote Procedure Call

Tanken bakom Remote Procedure Call (RPC) är att utöka den välkända och välkända mekanismen för att överföra kontroll och data inom ett program som körs på samma maskin till att överföra kontroll och data över ett nätverk. Fjärrproceduranropsverktyg är utformade för att underlätta organisationen av distribuerad datoranvändning. Den mest effektiva användningen av RPC uppnås i de applikationer där det finns en interaktiv kommunikation mellan fjärrkomponenter med en kort svarstid och en relativt liten mängd överförd data. Sådana applikationer kallas RPC-orienterade.

De framträdande egenskaperna för att ringa lokala procedurer är:

  • Asymmetri, det vill säga en av de interagerande parterna är initiativtagaren;
  • Synkronicitet, det vill säga exekveringen av anropsproceduren avbryts från det ögonblick då begäran utfärdas och återupptas först efter att den anropade proceduren återkommer.

Implementeringen av fjärrsamtal är mycket mer komplicerad än implementeringen av lokala procedursamtal. Till att börja med, eftersom anrops- och anropsprocedurerna körs på olika maskiner, har de olika adressutrymmen, och detta skapar problem vid överföring av parametrar och resultat, särskilt om maskinerna inte är identiska. Eftersom RPC inte kan förlita sig på delat minne, betyder detta att RPC-parametrar inte får innehålla pekare till icke-stackminnesplatser och att parametervärden måste kopieras från en dator till en annan. Nästa skillnad mellan RPC och lokal anrop är att det nödvändigtvis använder det underliggande kommunikationssystemet, men detta bör inte vara explicit synligt vare sig i definitionen av procedurer eller i själva procedurerna. Avstånd inför ytterligare problem. Exekveringen av det anropande programmet och den anropade lokala proceduren på samma maskin implementeras inom en enda process. Men det finns minst två processer involverade i RPC-implementering, en på varje maskin. Om en av dem kraschar kan följande situationer uppstå: om anropsproceduren kraschar, kommer de fjärranropade procedurerna att bli "föräldralösa", och om fjärrprocedurerna kraschar, kommer anropsprocedurerna att bli "utlösa föräldrar", vilket kommer att vänta på en svar från fjärrprocedurerna till ingen nytta.

Dessutom finns det ett antal problem förknippade med heterogeniteten hos programmeringsspråk och operativa miljöer: datastrukturer och proceduranropsstrukturer som stöds i ett programmeringsspråk stöds inte på samma sätt på alla andra språk.

Dessa och några andra problem löses av den utbredda RPC-tekniken som ligger till grund för många distribuerade operativsystem. Grundläggande RPC-operationer

För att förstå hur RPC fungerar, låt oss först överväga att göra ett lokalt proceduranrop på en vanlig dator som kör offline. Låt detta till exempel vara ett systemanrop

count=read(fd, buf, nbytes);

där fd är ett heltal, buf är en uppsättning tecken, nbytes är ett heltal.

För att ringa anropet trycker anropsproceduren parametrarna till stacken i omvänd ordning (Figur 3.1). Efter att anropet att läsa är gjort, placerar den returvärdet i ett register, flyttar returadressen och återgår kontrollen till anropsproceduren, som hämtar parametrarna från stacken och återställer den. Observera att i C kan parametrar anropas antingen genom referens (med namn) eller genom värde (efter värde). Med avseende på den anropade proceduren är värdeparametrar initierbara lokala variabler. Den anropade proceduren kan ändra dem, och detta kommer inte att påverka värdet på originalen av dessa variabler i anropsproceduren.

Om en pekare till en variabel skickas till den anropade proceduren, innebär ändring av värdet på denna variabel genom den anropade proceduren att ändra värdet på denna variabel för anropsproceduren. Detta faktum är mycket viktigt för RPC.

Det finns även en annan mekanism för att skicka parametrar som inte används i språket C. Den kallas call-by-copy/restore och består i att det anropande programmet måste kopiera variablerna till stacken som värden, och sedan kopiera dem tillbaka efter att samtalet har gjorts över de ursprungliga värdena för anropsproceduren.

Valet av vilken parameteröverföringsmekanism som ska användas är upp till språkdesignerna. Ibland beror det på vilken typ av data som överförs. I C, till exempel, skickas heltal och annan skalär data alltid genom värde, och matriser skickas alltid genom referens.

Ansökan

En betydande del av Windows-operativsystemets fjärrhanteringsverktyg (Event Viewer, Server Manager, utskriftshantering, användarlistor) använder DCE RPC som ett sätt för nätverkskommunikation mellan den hanterade tjänsten och den hanterande användargränssnittsapplikationen. DCE RPC-stöd har funnits i Windows NT sedan den allra första versionen 3.1. DCE RPC-klienter stöddes också på Windows 3.x/95/98/Me lite operativsystem.

Windows-systembiblioteken som tillhandahåller sådan kontroll och fungerar som basskikt för kontrollapplikationer för användargränssnitt (netapi32.dll och delvis advapi32.dll) innehåller faktiskt klientkoden för DCE RPC-gränssnitten som implementerar denna kontroll.

Detta arkitektoniska beslut var föremål för aktiv kritik av Microsoft. De generiska rangeringsrutinerna som finns i DCE RPC är mycket komplexa och har en enorm potential för att defekter kan utnyttjas i nätverket genom att skicka ett avsiktligt missformat DCE RPC-paket. En betydande del av Windows-säkerhetsbuggarna som upptäcktes från slutet av 90-talet till mitten av 2000-talet var buggar i DCE RPC-rangeringskoden.

Förutom DCE RPC använder Windows aktivt DCOM-teknik. Den används till exempel som ett kommunikationsmedel mellan IIS webbserverhanteringsverktyg och den hanterade servern själv. Ett fullfjädrat kommunikationsgränssnitt med MS Exchange Server-postsystemet - MAPI - är också baserat på DCOM.

Remote Procedure Call (RPC) Begreppet Remote Procedure Call

Tanken bakom Remote Procedure Call (RPC) är att utöka den välkända och välkända mekanismen för att överföra kontroll och data inom ett program som körs på samma maskin till att överföra kontroll och data över ett nätverk. Fjärrproceduranropsverktyg är utformade för att underlätta organisationen av distribuerad datoranvändning. Den mest effektiva användningen av RPC uppnås i de applikationer där det finns en interaktiv kommunikation mellan fjärrkomponenter med en kort svarstid och en relativt liten mängd överförd data. Sådana applikationer kallas RPC-orienterade.

De framträdande egenskaperna för att ringa lokala procedurer är:

Asymmetri, det vill säga en av de interagerande parterna är initiativtagaren; Synkronicitet, det vill säga exekveringen av anropsproceduren vid stopp från det ögonblick då begäran utfärdas och återupptas först efter återkomsten från den anropade proceduren.

Implementeringen av fjärrsamtal är mycket mer komplicerad än implementeringen av lokala procedursamtal. Till att börja med, eftersom anrops- och anropsprocedurerna körs på olika maskiner, har de olika adressutrymmen, och detta skapar problem vid överföring av parametrar och resultat, särskilt om maskinerna inte är identiska. Eftersom RPC inte kan förlita sig på delat minne, betyder detta att RPC-parametrar inte får innehålla pekare till icke-stackminnesplatser och att parametervärden måste kopieras från en dator till en annan. Nästa skillnad mellan RPC och lokal anrop är att det nödvändigtvis använder det underliggande kommunikationssystemet, men detta bör inte vara explicit synligt vare sig i definitionen av procedurer eller i själva procedurerna. Avstånd inför ytterligare problem. Exekveringen av det anropande programmet och den anropade lokala proceduren på samma maskin implementeras inom en enda process. Men det finns minst två processer involverade i RPC-implementering, en på varje maskin. Om en av dem kraschar kan följande situationer uppstå: om anropsproceduren kraschar, kommer de fjärranropade procedurerna att bli "föräldralösa", och om fjärrprocedurerna kraschar kommer anropsprocedurerna att bli "utlösa föräldrar" som väntar på ett svar från fjärrprocedurerna till ingen nytta.

Dessutom finns det ett antal problem förknippade med heterogeniteten hos programmeringsspråk och operativa miljöer: datastrukturer och proceduranropsstrukturer som stöds i ett programmeringsspråk stöds inte på samma sätt på alla andra språk.

Dessa och några andra problem löses av den utbredda RPC-tekniken som ligger till grund för många distribuerade operativsystem.

Grundläggande RPC-operationer

För att förstå hur RPC fungerar, låt oss först överväga att göra ett lokalt proceduranrop på en vanlig dator som kör offline. Låt detta till exempel vara ett systemanrop

Count=read(fd,buf,nbytes);

där fd är ett heltal,
buff - teckenuppsättning,
nbytes är ett heltal.

För att ringa anropet trycker anropsproceduren parametrarna till stacken i omvänd ordning (Figur 3.1). Efter att anropet att läsa är gjort, placerar den returvärdet i ett register, flyttar returadressen och återgår kontrollen till anropsproceduren, som hämtar parametrarna från stacken och återställer den. Observera att i C kan parametrar anropas antingen genom referens (med namn) eller genom värde (efter värde). Med avseende på den anropade proceduren är värdeparametrar initierbara lokala variabler. Den anropade proceduren kan ändra dem, och detta kommer inte att påverka värdet på originalen av dessa variabler i anropsproceduren.

Om en pekare till en variabel skickas till den anropade proceduren, innebär ändring av värdet på denna variabel genom den anropade proceduren att ändra värdet på denna variabel för anropsproceduren. Detta faktum är mycket viktigt för RPC.

Det finns även en annan mekanism för att skicka parametrar som inte används i språket C. Den kallas call-by-copy/restore och består i att det anropande programmet måste kopiera variablerna till stacken som värden, och sedan kopiera dem tillbaka efter att samtalet har gjorts över de ursprungliga värdena för anropsproceduren.

Valet av vilken parameteröverföringsmekanism som ska användas är upp till språkdesignerna. Ibland beror det på vilken typ av data som överförs. I C, till exempel, skickas heltal och annan skalär data alltid genom värde, och matriser skickas alltid genom referens.

Ris. 3.1. a) Stacken innan läsanropet exekveras;
b) Stapling under procedurexekvering;
c) Stapla efter återgång till det anropande programmet

Tanken bakom RPC är att få ett fjärrproceduranrop att se likadant ut som ett lokalt proceduranrop om möjligt. Med andra ord, gör RPC transparent: anropsproceduren behöver inte veta att den anropade proceduren finns på en annan maskin, och vice versa.

RPC uppnår transparens på följande sätt. När den anropade proceduren verkligen är avlägsen, placeras en annan version av proceduren, kallad en klientstub, i biblioteket istället för den lokala proceduren. Liksom den ursprungliga proceduren anropas stubben med hjälp av en anropssekvens (som i figur 3.1), och ett avbrott inträffar när man kommer åt kärnan. Bara till skillnad från den ursprungliga proceduren, lägger den inte in parametrar i register och ber inte kärnan om data, istället bildar den ett meddelande att skicka till kärnan på fjärrmaskinen.

RPC-exekveringssteg

Samspelet mellan programvarukomponenter när ett fjärranrop utförs illustreras i figur 3.2. Efter att klientstubben har anropats av klientprogrammet är dess första jobb att fylla bufferten med meddelandet den skickar. På vissa system har klientstubben en enda buffert med fast längd som fylls från början varje gång en ny begäran kommer. På andra system är meddelandebufferten en pool av buffertar för enskilda meddelandefält, av vilka några redan är fulla. Denna metod är särskilt lämplig för fall där paketet har ett format som består av ett stort antal fält, men värdena för många av dessa fält ändras inte från anrop till anrop.

Parametrarna måste sedan konverteras till lämpligt format och infogas i meddelandebufferten. Vid denna tidpunkt är meddelandet redo att sändas, så ett kärnavbrott exekveras.

Ris. 3.2. Fjärrproceduranrop

När kärnan får kontroll byter den sammanhang, sparar processorregistren och minneskartan (siddeskriptorer), skapar en ny minneskarta som ska användas för drift av kärnläget. Eftersom kärnan och användarkontexten är olika, måste kärnan kopiera meddelandet exakt till sitt eget adressutrymme, så att den kan komma åt det, komma ihåg destinationsadressen (och eventuellt andra rubrikfält), och den måste skicka det vidare till nätverket gränssnitt. Detta avslutar arbetet på kundsidan. Överföringstimern startar och kärnan kan antingen utföra en round-robin-undersökning för ett svar, eller överföra kontrollen till schemaläggaren, som väljer någon annan process att köra. I det första fallet accelereras exekveringen av frågor, men det finns ingen multiprogrammering.

På serversidan placeras de inkommande bitarna av den mottagande hårdvaran antingen i en inbyggd buffert eller i RAM. När all information har mottagits genereras ett avbrott. Avbrottshanteraren kontrollerar giltigheten av paketdata och bestämmer vilken stubb som ska skicka den. Om ingen av stubbarna förväntar sig detta paket måste hanteraren antingen buffra det eller kassera det helt. Om det finns en väntande stubb kopieras meddelandet till det. Slutligen utförs en kontextväxling, som återställer registren och minneskartan till de värden de hade när stubben ringde mottagningssamtalet.

Nu börjar serverstubben att fungera. Den packar upp parametrarna och skjuter dem på lämpligt sätt på stapeln. När allt är klart görs samtalet till servern. Efter att ha utfört proceduren skickar servern resultaten till klienten. För att göra detta utförs alla steg som beskrivs ovan, endast i omvänd ordning.

Figur 3.3 visar sekvensen av kommandon som måste utföras för varje RPC-anrop, och Figur 3.4 visar hur stor andel av den totala RPC-exekveringstiden som spenderas i vart och ett av dessa 14 steg. Testerna utfördes på en DEC Firefly-arbetsstation med flera processorer, och medan närvaron av fem processorer nödvändigtvis påverkade mätningarna, ger histogrammet som visas i figuren en allmän uppfattning om RPC-utförandet.

Ris. 3.3. Steg i RPC-proceduren

Ris. 3.4. Fördelning av tid mellan 14 stadier av RPC-utförande

1. Ring stum

2. Förbered buffert

3. Packa alternativ

4. Fyll i rubrikfältet

5. Beräkna kontrollsumman i meddelandet

6. Avbryt till kärnan

7. Paketkörningskö

8. Skickar ett meddelande till regulatorn via QBUS

9. Ethernet-överföringstid

10. Ta emot ett paket från styrenheten

11. Avbryt hanteringsprocedur

12. Kontrollsummaberäkning

13. Kontextväxling till användarutrymme

14. Kör serverstub

Dynamisk länkning

Tänk på frågan om hur klienten anger serverns plats. Ett sätt att lösa detta problem är att direkt använda serverns nätverksadress i klientprogrammet. Nackdelen med detta tillvägagångssätt är att det är extremt oflexibelt: när du flyttar en server, eller när du ökar antalet servrar, eller när du ändrar gränssnittet, i alla dessa och många andra fall, måste du kompilera om alla program som använde hårt serveradressinställning. För att undvika alla dessa problem använder vissa distribuerade system något som kallas dynamisk länkning.

Utgångspunkten för dynamisk bindning är den formella definitionen (specifikationen) av servern. Specifikationen innehåller filserverns namn, versionsnummer och en lista över serviceprocedurer som tillhandahålls av denna server för klienter (figur 3.5). För varje procedur ges en beskrivning av dess parametrar, som anger om denna parameter är en in- eller utgångsparameter i förhållande till servern. Vissa parametrar kan vara både input och output - till exempel en array som skickas av klienten till servern, modifieras där och sedan returneras tillbaka till klienten (kopiera/återställning).

Ris. 3.5. RPC-serverspecifikation

Den formella serverspecifikationen används som indata till stubbgeneratorprogrammet som skapar både klient- och serverstubbar. Sedan placeras de i lämpliga bibliotek. När ett användarprogram (klient) anropar någon procedur som definieras i serverspecifikationen, associeras motsvarande stubbprocedur med programmets binära program. På samma sätt, när en server kompileras, associeras serverstubbar med den.

När en server startar är dess allra första åtgärd att skicka dess servergränssnitt till ett speciellt program som kallas binder. Denna process, känd som serverregistreringsprocessen, innebär att servern skickar sitt namn, versionsnummer, unika identifierare och ett handtag. till serverns plats Handtaget är systemoberoende och kan vara en IP-, Ethernet-, X.500-adress etc. Det kan även innehålla annan information som autentisering.

När en klient anropar en av fjärrprocedurerna för första gången, som t.ex. read, ser klientstubben att den ännu inte är ansluten till servern och skickar ett meddelande till bindern som ber den att importera gränssnittet för den önskade versionen av önskad server. Om en sådan server finns skickar bindaren handtaget och den unika identifieraren till klientstubben.

Klientstubben, när den skickar ett meddelande med en begäran, använder en deskriptor som adress. Meddelandet innehåller parametrar och en unik identifierare, som servermotorn använder för att dirigera det inkommande meddelandet till rätt server om det finns flera av dem på den här maskinen.

Denna metod för att importera/exportera gränssnitt är mycket flexibel. Till exempel kan det finnas flera servrar som stöder samma gränssnitt, och klienterna tilldelas slumpmässigt till servrarna. Som en del av denna metod blir det möjligt att regelbundet polla servrar, analysera deras hälsa och, i händelse av fel, automatiskt stänga av, vilket ökar systemets totala feltolerans. Den här metoden kan också stödja klientautentisering. Servern kan till exempel bestämma att den endast kan användas av klienter från en viss lista.

Dynamisk bindning har dock nackdelar, såsom extra overhead (tidskostnader) för export och import av gränssnitt. Denna kostnad kan vara betydande, eftersom många klientprocesser existerar under en kort tid, och varje gång processen startar måste gränssnittsimportproceduren utföras igen. Dessutom kan bindeprogrammet i stora distribuerade system bli en flaskhals, och att skapa flera program med samma syfte ökar också omkostnader för att skapa och synkronisera processer.

RPC-semantik vid misslyckanden

Helst ska RPC fungera korrekt i händelse av fel. Tänk på följande felklasser:

Klienten kan inte bestämma serverns plats, till exempel om den önskade servern misslyckas eller för att klientprogrammet kompilerades för länge sedan och använde en gammal version av servergränssnittet. I detta fall, som svar på en klientförfrågan, mottas ett meddelande som innehåller en felkod. Förlorad begäran från klient till server. Den enklaste lösningen är att upprepa begäran efter en viss tid. Förlorat svarsmeddelande från server till klient. Det här alternativet är mer komplicerat än det föregående, eftersom vissa procedurer inte är idempotenta. En idempotent procedur är en procedur vars exekveringsbegäran kan upprepas flera gånger utan att resultatet ändras. Ett exempel på en sådan procedur skulle vara att läsa en fil. Men proceduren för att ta ut ett visst belopp från ett bankkonto är inte idempotent, och om svaret går förlorat kan en upprepad begäran avsevärt ändra tillståndet för kundens konto. En möjlig lösning är att göra alla procedurer idempotenta. Men i praktiken är detta inte alltid möjligt, så en annan metod kan användas - sekventiell numrering av alla förfrågningar av klientkärnan. Serverkärnan kommer ihåg numret på den senaste begäran från var och en av klienterna, och vid mottagandet av varje begäran analyserar den om denna begäran är primär eller upprepad. Servern kraschade efter att ha tagit emot begäran. Egenskapen idempotens är också viktig här, men tyvärr kan frågenumreringsmetoden inte tillämpas. I det här fallet spelar det roll när felet inträffade - före eller efter operationen. Men klientkärnan kan inte känna igen dessa situationer, den vet bara att svaret har tagit timeout. Det finns tre tillvägagångssätt för detta problem: Vänta tills servern startar om och försök igen. Detta tillvägagångssätt säkerställer att RPC har slutförts minst en gång, och möjligen fler. Rapportera felet till applikationen omedelbart. Detta tillvägagångssätt säkerställer att RPC:n har körts högst en gång. Det tredje tillvägagångssättet garanterar ingenting. När servern misslyckas ges inget stöd till klienten. RPC:n kan antingen inte exekveras alls, eller så kan den exekveras många gånger. I vilket fall som helst är denna metod mycket lätt att implementera.

Inget av dessa tillvägagångssätt är särskilt attraktivt. Och det ideala alternativet, som skulle garantera exakt en RPC-exekvering, kan i det allmänna fallet inte implementeras av grundläggande skäl. Anta till exempel att fjärroperationen är att skriva ut lite text, vilket innebär att ladda skrivarens buffert och ställa in en bit i något skrivarkontrollregister, vilket gör att skrivaren startar. En serverkrasch kan inträffa antingen en mikrosekund före eller en mikrosekund efter att kontrollbiten är inställd. Felögonblicket avgör helt och hållet återställningsproceduren, men klienten kan inte ta reda på felögonblicket. Kort sagt, möjligheten för en serverkrasch förändrar radikalt karaktären hos RPC och återspeglar tydligt skillnaden mellan ett centraliserat och ett distribuerat system. I det första fallet leder en serverkrasch till en klientkrasch och återställning är omöjlig. I det andra fallet är åtgärderna för att återställa systemet både möjliga och nödvändiga.

Klienten kraschade efter att ha skickat begäran. I det här fallet görs beräkningar på resultat som ingen förväntar sig. Sådana beräkningar kallas "föräldralösa". Förekomsten av föräldralösa barn kan orsaka olika problem: slöseri med CPU-tid, blockering av resurser, ersättande av svaret på den aktuella begäran med svaret på begäran som utfärdades av klientdatorn innan systemet startades om.

Hur hanterar man föräldralösa barn? Fundera på 4 möjliga lösningar.

Förstörelse. Innan en klientstub skickar ett RPC-meddelande gör den en loggpost som berättar vad den kommer att göra härnäst. Loggen lagras på disk eller annat feltolerant minne. Efter kraschen startas systemet om, loggen analyseras och de föräldralösa barnen elimineras. Nackdelarna med detta tillvägagångssätt är för det första den ökade kostnaden förknippad med att skriva varje RPC till disk, och för det andra den möjliga ineffektiviteten på grund av uppkomsten av andra generationens föräldralösa barn som genereras av RPC:er som utfärdats av första generationens föräldralösa barn. Reinkarnation. I det här fallet löses alla problem utan att använda diskskrivning. Metoden består i att dela upp tiden i på varandra följande numrerade perioder. När klienten startar om sänder den ett meddelande till alla maskiner om början av en ny period. Vid mottagande av detta meddelande avslutas alla fjärrberäkningar. Naturligtvis, om nätverket är segmenterat, kan vissa föräldralösa barn överleva. Mjuk reinkarnation liknar det tidigare fallet, förutom att inte alla fjärrberäkningar hittas och förstörs, utan bara beräkningarna från den omstartade klienten. Utgång. Varje begäran får en standardtid T, under vilken den måste slutföras. Om begäran inte slutförs inom den tilldelade tiden, tilldelas ytterligare ett kvantum. Även om detta kräver ytterligare arbete, om servern efter en klientkrasch väntar på ett intervall T innan klienten startar om, så förstörs nödvändigtvis alla föräldralösa barn.

I praktiken är inget av dessa tillvägagångssätt önskvärt, dessutom kan förstörelse av föräldralösa barn förvärra situationen. Anta till exempel att ett föräldralöst barn har låst en eller flera databasfiler. Om ett föräldralöst barn plötsligt förstörs, kommer dessa lås att finnas kvar, dessutom kan förstörda föräldralösa barn stå kvar i olika systemköer, i framtiden kan de orsaka exekvering av nya processer, etc.

Program som kommunicerar över ett nätverk behöver en kommunikationsmekanism. På den lägre nivån, vid ankomsten av paket, sänds en signal, som bearbetas av nätverkssignalbehandlingsprogrammet. På den översta nivån fungerar mötesmekanismen (rendezvous) som används i Ada-språket. NFS använder en RPC-mekanism (Remote Procedure Call) där klienten kommunicerar med servern (se figur 1). Enligt denna process anropar klienten först en procedur som skickar en begäran till servern. Vid ankomsten av ett paket med en begäran anropar servern proceduren för att öppna den, utför den begärda tjänsten, skickar ett svar och kontrollen returneras till klienten.

RPC-gränssnittet kan ses som att det består av tre lager:

Den översta nivån är helt "transparent". Ett program på denna nivå kan till exempel innehålla ett anrop till proceduren rnusers(), som returnerar antalet användare på fjärrdatorn. Du behöver inte veta om att använda RPC-mekanismen så länge du ringer i programmet.

Mellanskiktet är för de vanligaste applikationerna. RPC-anrop på denna nivå hanteras av subrutinerna registerrpc() och callrpc(): registerrpc() får systemomfattande kod och callrpc() utför ett fjärrproceduranrop. Anropet till rnusers() implementeras med dessa två subrutiner.

Den lägre nivån används för mer komplexa uppgifter som ändrar standardvärdena till procedurens parametervärden. På den här nivån kan du explicit manipulera uttagen som används för att skicka RPC-meddelanden.

Som en allmän regel bör du använda den övre nivån och undvika att använda de lägre nivåerna om det inte är absolut nödvändigt.

Även om vi bara täcker C-gränssnittet i denna handledning, kan fjärranrop göras från vilket språk som helst. Funktionen av RPC-mekanismen för att organisera kommunikation mellan processer på olika maskiner skiljer sig inte från dess funktion på samma maskin.

RPC (Remote Procedure Call, Remote Procedure Call Service) är ett gränssnitt mellan fjärranvändare och vissa värdprogram som körs på begäran av dessa användare. En värds RPC-tjänst tillhandahåller vanligtvis en uppsättning program till klienter. Vart och ett av dessa program består i sin tur av en eller flera fjärrprocedurer. Till exempel kan en fjärransluten NFS-tjänst som är byggd på RPC-anrop bestå av endast två program: till exempel interagerar ett program med användargränssnitt på hög nivå och det andra med I/O-funktioner på låg nivå.

Det finns två parter involverade i varje fjärrproceduranrop: den aktiva klienten, som skickar en proceduranropsbegäran till servern, och servern som skickar ett svar tillbaka till klienten.

Notera. Tänk på att termerna "klient" och "server" i det här fallet hänvisar till en specifik transaktion. En viss värd eller programvara (process eller program) kan fungera som både klient och server. Till exempel kan ett program som tillhandahåller en fjärrprocedurtjänst också vara en klient som arbetar med ett nätverksfilsystem.

RPC-protokollet är byggt på en fjärrproceduranropsmodell liknande den för lokala proceduranrop. När du anropar en lokal procedur placerar du argumenten på en specifik plats i minnet, på stacken eller i miljövariabler och överför kontrollen över processen till en specifik adress. När du är klar läser du resultaten på en specifik adress och fortsätter med din process.

När det gäller att arbeta med en fjärrprocedur är den största skillnaden att fjärrfunktionsanropet betjänas av två processer: klientprocessen och serverprocessen.

Klientprocessen skickar ett meddelande till servern, som inkluderar parametrarna för den anropade proceduren, och väntar på ett svarsmeddelande med resultatet av dess arbete. När ett svar tas emot läses resultatet och processen fortsätter. På serversidan är samtalshanterarprocessen i vänteläge, och när ett meddelande kommer, läser den procedurens parametrar, exekverar den, skickar ett svar och blir i vänteläge för nästa samtal.

RPC-protokollet ställer inga krav på ytterligare kommunikationer mellan processer och kräver inte synkronisering av de utförda funktionerna, d.v.s. samtal kan vara asynkrona och ömsesidigt oberoende, så att klienten kan utföra andra procedurer medan de väntar på ett svar. RPC-servern kan tilldela en separat process eller virtuell maskin för varje funktion, därför kan den, utan att vänta på att de tidigare förfrågningarna ska avslutas, omedelbart acceptera nästa.

Det finns dock flera viktiga skillnader mellan lokala och fjärranrop:

1. Fel vid bearbetning. Klienten bör i alla fall meddelas om fel som uppstår vid fjärranrop på servern eller på nätverket.

2. Globala variabler. Eftersom servern inte har tillgång till klientens adressutrymme kan fjärranrop inte använda dolda parametrar som globala variabler.

3. Prestanda. Exekveringshastigheten för fjärrprocedurer är som regel en eller två storleksordningar lägre än exekveringshastigheten för liknande lokala procedurer.

4. Autentisering. Eftersom fjärranrop sker över nätverket måste klientautentiseringsmekanismer användas.

Protokollkonstruktionsprinciper.

RPC-protokollet kan använda flera olika transportprotokoll. RPC-protokollets ansvar är endast att tillhandahålla standarder och tolka meddelandeöverföring. Tillförlitligheten och tillförlitligheten för meddelandeöverföring tillhandahålls helt och hållet av transportskiktet.

RPC kan dock styra valet och vissa funktioner i transportprotokollet. Som ett exempel på interaktionen mellan RPC och transportprotokollet, överväg proceduren för att tilldela RPC-porten för en applikationsprocess genom RPC - Portmapper.

Denna funktion tilldelar dynamiskt (på begäran) en specifik port till en RPC-anslutning. Fungera Portmapper används ganska ofta, eftersom uppsättningen av transportportar reserverade för RPC är begränsad, och antalet processer som potentiellt kan fungera samtidigt är mycket högt. Portmapper, till exempel, anropas när klient- och serverkommunikationsportarna för NFS-systemet är valda.

Service Portmapper använder RPC broadcast-meddelandemekanismen på en specifik port - III. På den här porten skickar klienten ett utsändningsmeddelande för portbegäran för en specifik RPC-tjänst. Service Portmapper behandlar meddelandet, bestämmer adressen till den lokala RPC-tjänsten och skickar ett svar till klienten. Service RPC Portmapper kan fungera med både TCP- och UDP-protokoll.

RPC kan arbeta med olika transportprotokoll, men duplicerar aldrig deras funktioner, d.v.s. om RPC fungerar ovanpå TCP tilldelas alla bekymmer om RPC-anslutningens tillförlitlighet och tillförlitlighet till TCP. Men om RPC är installerat över UDP kan det ge ytterligare inbyggda funktioner för att säkerställa meddelandeleverans.

Notera. Applikationsuppgifter kan betrakta RPC-protokollet som en specifik procedur för att anropa en funktion över ett JSR-nätverk (Jump Subroutine Instruction).

För att RPC-protokollet ska fungera måste följande villkor vara uppfyllda:

1. Unik identifiering av alla fjärranropade procedurer på en given värd. RPC-begäranden innehåller tre identifierarfält - numret på fjärrprogrammet (tjänsten), versionsnumret för fjärrprogrammet och numret på fjärrproceduren för det angivna programmet. Programnumret tilldelas av tillverkaren av tjänsten, procedurnumret indikerar den specifika funktionen för denna tjänst

2. Identifiering av RPC-protokollets version. RPC-meddelanden innehåller ett RPC-protokollversionsfält. Den används för att koordinera formaten för överförda parametrar när klienten arbetar med olika versioner av RPC.

3. Tillhandahålla mekanismer för klientautentisering på servern. RPC-protokollet tillhandahåller en procedur för att autentisera klienten i tjänsten, och, om nödvändigt, med varje begäran eller skicka ett svar till klienten. Dessutom tillåter RPC olika ytterligare säkerhetsmekanismer att användas.

RPC kan använda fyra typer av autentiseringsmekanismer:

AUTH_NULL - ingen autentisering

AUTH_UNIX - UNIX standardautentisering

AUTH_SHORT - UNIX standardautentisering med egen kodningsstruktur

AUTH_DES - DES-autentisering

4. Identifiering av svarsmeddelanden på motsvarande förfrågningar. RPC-svarsmeddelanden innehåller begäran-ID från vilket de byggdes. Detta ID kan kallas transaktions-ID för RPC-anropet. Denna mekanism är särskilt nödvändig när man arbetar i asynkront läge och när man kör en sekvens av flera RPC-anrop.

5. Identifiering av protokolldriftsfel. Alla nätverks- eller serverfel har unika identifierare, med vilka var och en av deltagarna i anslutningen kan fastställa orsaken till felet.

Protokollmeddelandestrukturer

När RPC-meddelanden sänds över ett transportprotokoll kan flera RPC-meddelanden finnas inom ett enda transportpaket. För att separera ett meddelande från ett annat används en postmarkör (RM - Record Marker). Varje RPC-meddelande är "taggat" med exakt en RM.

Ett RPC-meddelande kan bestå av flera fragment. Varje fragment består av fyra rubrikbyte och (från 0 till 2**31-1) data. Den första biten i rubriken indikerar om det givna fragmentet är det sista, och de återstående 31 bitarna indikerar längden på datapaketet.

RPC:s struktur beskrivs formellt på språket för beskrivning och representation av dataformat - XDR med tillägg angående beskrivning av procedurer. Man skulle till och med kunna säga att RPC-beskrivningsspråket är en förlängning av XDR, kompletterat med arbete med procedurer.

Strukturen för ett RPC-paket ser ut så här:

struct rpc_msg (

osignerad int xid;

union switch (msg_type mtype) (

call_body cbody;

svar kropp rbody;

där xid är identifieraren för den aktuella transaktionen, call_body är begäranspaketet, reply_body är svarspaketet. Förfrågningsstrukturen ser ut ungefär så här:

struct call body(

osignerade int rpcvers;

osignerad int prog;

osignerad int vers;

osignerad int proc;

opaque_auth cred;

opaque_authverf;

/* procedurparametrar */

Svarsstrukturen (reply_body) kan innehålla antingen en struktur som skickas i händelse av ett fel (i vilket fall den innehåller felkoden), eller en struktur som framgångsrikt bearbetade begäran (i vilket fall den innehåller de returnerade data).

Programmeringsgränssnitt på hög nivå.

Användningen av subrutiner i ett program är det traditionella sättet att strukturera en uppgift, för att göra den tydligare. De vanligaste rutinerna samlas i bibliotek där de kan användas av olika program. I det här fallet talar vi om ett lokalt (lokalt) samtal, dvs både det anropande och det anropade objektet fungerar inom samma program på samma dator.

I ett fjärrsamtal startar en process som körs på en dator en process på fjärrdatorn (det vill säga den kör faktiskt procedurkoden på fjärrdatorn). Uppenbarligen skiljer sig ett fjärrproceduranrop avsevärt från ett traditionellt lokalt, men ur programmerarens synvinkel finns det praktiskt taget inga sådana skillnader, dvs. fjärrprocedurens anropsarkitektur tillåter dig att simulera ett lokalt samtal.

Men om, i fallet med ett lokalt samtal, programmet skickar parametrar till den anropade proceduren och tar emot resultatet av arbetet genom stacken eller delade minnesområdena, då i fallet med ett fjärrsamtal, förvandlas överföring av parametrar till att skicka en begäran över nätverket, och resultatet av arbetet finns i det inkommande svaret.

Detta tillvägagångssätt är en möjlig grund för att skapa distribuerade applikationer, och även om många moderna system inte använder denna mekanism, finns de grundläggande begreppen och termerna i många fall kvar. När vi beskriver RPC-mekanismen kommer vi traditionellt att referera till anropsprocessen som klienten och fjärrprocessen som implementerar proceduren som servern.

Ett fjärranrop innehåller följande steg:

1. Klientprogrammet gör ett lokalt anrop till en procedur som kallas stubb. Samtidigt "verkar" det för klienten att den, genom att anropa stubben, faktiskt anropar serverproceduren. Faktum är att klienten skickar de nödvändiga parametrarna till stubben och den returnerar resultatet. Situationen är dock inte riktigt som klienten föreställer sig. Stubbens uppgift är att acceptera argument avsedda för fjärrproceduren, kanske konvertera dem till något standardformat och bilda en nätverksbegäran. Att packa argument och göra en nätverksbegäran kallas för rangering.

2. Nätverksbegäran skickas över nätverket till fjärrsystemet. För att göra detta använder stubben lämpliga anrop, såsom de som diskuterats i tidigare avsnitt. Observera att olika transportprotokoll kan användas i detta fall, och inte bara TCP/IP-familjerna.

3. På fjärrvärden sker allt i omvänd ordning. Serverstubben väntar på en förfrågan och, när den tas emot, hämtar parametrar - procedurens anropsargument. Extraktion (unmarshalling) kan innefatta nödvändiga transformationer (till exempel omordning av bytes).

4. Stubben gör ett anrop till den verkliga serverproceduren till vilken klientens förfrågan är adresserad och skickar den mottagna argumenten över nätverket.

5. Efter att ha utfört proceduren återgår kontrollen till serverstubben och skickar de nödvändiga parametrarna till den. Liksom klientstubben; serverstubben konverterar värdena som returneras av proceduren för att bilda ett nätverkssvarsmeddelande som skickas över nätverket till systemet från vilket förfrågan kom.

6. Operativsystemet skickar det mottagna meddelandet till klientstubben, som efter den nödvändiga transformationen skickar värdena (som är de värden som returneras av fjärrproceduren) till klienten, som tolkar detta som en normal retur från förfarandet.

Från klientens synvinkel ringer han alltså ett förfarande på distans, precis som han skulle göra för ett lokalt. Detsamma kan sägas om servern: proceduren anropas på vanligt sätt, något objekt (serverstub) anropar den lokala proceduren och tar emot värdena som returneras av det. Klienten behandlar stubben som en anropsbar serverprocedur, och servern tar sin egen stubb som klient.

Således utgör stubbar kärnan i RPC-systemet, ansvarig för alla aspekter av att generera och skicka meddelanden mellan klienten och fjärrservern (procedur), även om både klient och server anser att samtalen ska göras lokalt. Detta är huvudkonceptet för RPC - att helt dölja den distribuerade (nätverks)naturen för interaktionen i stubbkoden. Fördelarna med detta tillvägagångssätt är uppenbara: både klienten och servern är oberoende av nätverksimplementeringen, de arbetar båda inom en distribuerad virtuell maskin och proceduranropen har ett standardgränssnitt.

Passerar parametrar

Att passera värdeparametrar är inte svårt. I det här fallet placerar klientstubben värdet på parametern i nätverksbegäran, kanske genom att utföra standardkonverteringar (till exempel ändra endianness). Situationen är mycket mer komplicerad med att skicka pekare när parametern är adressen till data och inte deras värde. Att skicka en adress i begäran är meningslöst eftersom fjärrproceduren körs i ett helt annat adressutrymme. Den enklaste lösningen som används i RPC är att förhindra att klienter skickar andra parametrar än efter värde, även om detta verkligen medför allvarliga begränsningar.

Bindande

Innan en klient kan anropa en fjärrprocedur måste den vara associerad med ett fjärrsystem som har den nödvändiga servern. Således är uppgiften att binda uppdelad i två:

Hitta en fjärrvärd med en önskad server

Att hitta den nödvändiga serverprocessen på en given värd

Olika metoder kan användas för att hitta en värd. Ett möjligt alternativ är att skapa någon form av centraliserad katalog där värdar tillkännager sina servrar, och där klienten, om så önskas, kan välja värd och adress för proceduren som passar honom.

Varje RPC-procedur identifieras unikt av ett program- och procedurnummer. Programnumret definierar en grupp av fjärrprocedurer, som var och en har sitt eget nummer. Varje program tilldelas också ett versionsnummer, så om du gör mindre ändringar i programmet (till exempel lägger till en procedur) behöver du inte ändra dess nummer. Vanligtvis implementeras flera funktionellt likartade procedurer i en programmodul, som, när den startas, blir servern för dessa procedurer, och som identifieras av programnumret.

Sålunda, när en klient vill anropa en fjärrprocedur, måste den känna till programmet, versionen och procedurnumren som tillhandahåller den erforderliga tjänsten.

För att skicka en begäran måste klienten också känna till värdens nätverksadress och portnumret som är associerat med serverprogrammet som tillhandahåller de nödvändiga procedurerna. Detta görs med hjälp av portmap(IM)-demonen (kallad rpcbind(IM) på vissa system). Demonen körs på en värd som tillhandahåller en fjärrprocedurtjänst och använder ett välkänt portnummer. När en serverprocess initieras, registrerar den dess procedurer och portnummer i portmap(IM). Nu, när klienten behöver veta portnumret för att anropa en viss procedur, skickar den en begäran till portmap(IM)-servern, som i sin tur antingen returnerar portnumret eller vidarebefordrar begäran direkt till fjärrprocedurservern och returnerar ett svar till klienten när det körs. I alla fall, om den nödvändiga proceduren finns, får klienten portnumret för proceduren från portmap(IM)-servern och kan göra ytterligare förfrågningar direkt till denna port.

Hantering av speciella situationer (undantag)

Att hantera undantag när man anropar lokala rutiner är inte något större problem. UNIX tillhandahåller hantering av processfel såsom division med noll, åtkomst till ett ogiltigt minnesområde etc. Vid ett fjärranrop ökar sannolikheten för felsituationer. Fel relaterade till att till exempel ta emot ett felaktigt nätverksmeddelande har lagts till på server- och stubbfel.

Till exempel, när man använder UDP som transportprotokoll, sänds meddelanden om efter en viss timeout. Ett fel returneras till klienten om det efter ett visst antal försök inte har mottagits något svar från servern. I det fall då TCP-protokollet används, returneras ett fel till klienten om servern avslutade TCP-anslutningen.

Ring semantik

Att anropa en lokal procedur leder otvetydigt till dess exekvering, varefter kontrollen återgår till huvudprogrammet. Situationen är annorlunda när man anropar en fjärrprocedur. Det är omöjligt att avgöra exakt när proceduren kommer att utföras, om den kommer att utföras överhuvudtaget och i så fall hur många gånger? Till exempel, om begäran tas emot av fjärrsystemet efter att serverprogrammet kraschar, kommer proceduren inte att utföras alls. Om klienten inte tar emot ett svar efter en viss tidsperiod (timeout), skickar om begäran kan en situation uppstå när svaret redan har sänts över nätverket och den upprepade begäran accepteras igen för behandling av fjärrproceduren . I det här fallet kommer proceduren att utföras flera gånger.

Sålunda kan exekveringen av en fjärrprocedur karakteriseras av följande semantik:

- En och bara en gång. Detta beteende (i vissa fall det mest önskvärda) är svårt att kräva på grund av möjliga serverkrascher.

- Maxtider. Detta innebär att proceduren antingen inte utfördes alls eller bara utfördes en gång. Ett liknande påstående kan göras när man får ett fel istället för ett normalt svar.

- Åtminstone en gång. Proceduren utfördes förmodligen en gång, men mer är möjligt. För normal drift i en sådan situation måste fjärrproceduren ha egenskapen idempotent (från den engelska idemponenten). Den här egenskapen har en procedur vars upprepad körning inte orsakar kumulativa ändringar. Till exempel är det idempotent att läsa en fil, men att lägga till text i en fil är det inte.

Datarepresentation

När klienten och servern körs på samma system på samma dator finns det inga datainkompatibilitetsproblem. Både för klienten och för servern presenteras data i binär form på samma sätt. I fallet med ett fjärranrop kompliceras saken av att klienten och servern kan köras på system med olika arkitekturer som har olika datarepresentationer (till exempel representationen av ett flyttalsvärde, byteordning, etc.)

De flesta implementeringar av RPC-systemet definierar några standarddatarepresentationer till vilka alla värden som skickas i förfrågningar och svar måste konverteras.

Datarepresentationsformatet i Sun Microsystems RPC är till exempel följande:

Byte Order - Största sist

Representerar flyttalsvärden - IEEE

Karaktärsrepresentation - ASCII

RPC-systemet intar i sin funktionalitet en mellanposition mellan applikationsskiktet och transportskiktet. I enlighet med OSI-modellen motsvarar denna bestämmelse presentations- och sessionslagren. Således är RPC teoretiskt oberoende av implementeringen av nätverket, i synnerhet av nätverksprotokollen för transportskiktet.

Programvaruimplementationer av systemet stöder som regel ett eller två protokoll. Till exempel stöder Sun Microsystems RPC-system meddelandeöverföring med TCP- och UDP-protokollen. Valet av ett eller annat protokoll beror på applikationens krav. Valet av UDP-protokoll är motiverat för applikationer med följande egenskaper:

Kallade procedurer är idempotenta

Storleken på de godkända argumenten och det returnerade resultatet är mindre än storleken på UDP-paketet - 8 KB.

Servern ger arbete med flera hundra klienter. Eftersom servern tvingas upprätthålla en anslutning med var och en av de aktiva klienterna när den arbetar med TCP-protokoll, tar detta upp en betydande del av dess resurser. UDP-protokollet är mindre resurskrävande i detta avseende.

Å andra sidan möjliggör TCP effektiv drift av applikationer med följande egenskaper:

Applikationen kräver ett tillförlitligt överföringsprotokoll

Kallade procedurer är icke-komponenter

Storleken på argumenten eller returresultatet överstiger 8 KB

Valet av protokoll förblir vanligtvis hos klienten, och systemet organiserar bildandet och överföringen av meddelanden på olika sätt. Så när du använder TCP-protokollet, för vilket de överförda data är en ström av byte, är det nödvändigt att separera meddelanden från varandra. För att göra detta används till exempel postmarkeringsprotokollet som beskrivs i RFC1057 "RPC: Remote Procedure Call Protocol specification version 2", där ett 32-bitars heltal placeras i början av varje meddelande, som anger storleken på meddelandet i byte.

Situationen är annorlunda med samtalets semantik. Till exempel, om RPC utförs med hjälp av ett opålitligt transportprotokoll (UDP), återsänder systemet meddelandet med korta intervall (timeouts). Om klientapplikationen inte får något svar, är det säkert att säga att proceduren har utförts noll eller fler gånger. Om ett svar inkommit kan ansökan dra slutsatsen att ingreppet utförts minst en gång. Med Trusted Transport Protocol (TCP), om ett svar tas emot, kan man säga att proceduren utfördes en gång. Om svaret inte tas emot är det omöjligt att definitivt säga att proceduren inte utfördes3.

Hur det fungerar?

I huvudsak är själva RPC-systemet inbyggt i klientprogrammet och serverprogrammet. Den goda nyheten är att när du utvecklar distribuerade applikationer behöver du inte fördjupa dig i detaljerna i RPC-protokollet eller programmeddelandebehandling. Systemet förutsätter att det finns en lämplig utvecklingsmiljö, vilket avsevärt förenklar livet för skaparna av applikationsprogramvara. En av nyckelpunkterna i RPC är att utvecklingen av en distribuerad applikation börjar med definitionen av ett objektgränssnitt - en formell beskrivning av serverns funktioner, gjord på ett speciellt språk. Baserat på detta gränssnitt genereras sedan klient- och serverstubbar automatiskt. Det enda du kan göra efter det är att skriva själva procedurkoden.

Som ett exempel, överväg RPC från Sun Microsystems. Systemet består av tre huvuddelar:

Rpcgen(1) är en RPC-kompilator som, baserat på beskrivningen av fjärrprocedurens gränssnitt, genererar klient- och serverstubbar i form av C-program.

XDR-biblioteket (eXternal Data Representation), som innehåller funktioner för att konvertera olika typer av data till en maskinoberoende form, vilket möjliggör utbyte av information mellan heterogena system.

Ett bibliotek med moduler som säkerställer driften av systemet som helhet.

Låt oss överväga ett exempel på den enklaste distribuerade händelseloggningsapplikationen. Klienten anropar vid start en fjärrprocedur för att skriva ett meddelande till fjärrdatorns loggfil.

För att göra detta måste du skapa minst tre filer: specifikationen för log.x-fjärrprocedurgränssnitten (i gränssnittsbeskrivningsspråket), den faktiska texten för log.c-fjärrprocedurerna och texten för klientens huvud program main () - client.c (på C-språket).

rpcgen(l)-kompilatorn genererar tre filer baserat på log.x-specifikationen: texten för klient- och serverstubbarna på C-språket (log clnt.c och log svc.c) och beskrivningsfilen log.h som används av båda stubbarna .

Så låt oss titta på källkoden för programmen.

Den här filen specificerar registreringsparametrarna för fjärrproceduren - program-, versions- och procedurnummer, och definierar även anropsgränssnittet - inmatningsargument och returvärden. Sålunda definieras RLOG-proceduren och tar som argument en sträng (som kommer att skrivas till loggen), och returvärdet indikerar som standard framgång eller misslyckande för den beställda operationen.

program LOG_PROG(

version LOG_VER(

int RLOG(sträng) = 1;

) = 0x31234567;

rpcgen(l)-kompilatorn skapar en rubrikfil log.h, där i synnerhet procedurerna är definierade:

log.h

* Vänligen redigera inte den här filen.

* Det genererades med rpcgen.

#ifndef _LOG_H_RPCGEN

#define _LOG_H_RPCGEN

#omfatta

/* Programnummer */

#define LOG_PROG ((osignerad lång) (0x31234567))

#define LOG_VER ((osignerad lång) (1)) /*Versionsnummer*/

#define RLOG ((osignerad lång) (1)) /*Procedurnummer*/

extern int *rlog_l () ;

/* Intern procedur - vi behöver inte använda den */ extern int log_prog_l_freeresult();

#endif /* !_LOG_H_RPCGEN */

Låt oss titta närmare på den här filen. Kompilatorn översätter RLOG-namnet som definieras i gränssnittets definitionsfil till rlog_1, ersätter versaler med gemener och lägger till programmets versionsnummer med ett understreck. Returtypen har ändrats från int till int *. Detta är regeln - RPC låter dig skicka och ta emot endast adresserna till parametrarna som deklareras i beskrivningen av gränssnittet. Samma regel gäller för strängen som skickas som ett argument. Även om filen print.h inte antyder detta, skickas faktiskt adressen till raden också som ett argument till funktionen rlog_l ().

Förutom header-filen genererar rpcgen(l)-kompilatorn klientstub- och serverstubmoduler. I huvudsak innehåller texten i dessa filer all fjärranropskod.

Serverstubben är värdprogrammet som hanterar all nätverksinteraktion med klienten (mer exakt, med dess stubb). För att utföra operationen gör serverstubben ett lokalt funktionsanrop, vars text måste skrivas:

log.c

#omfatta

#omfatta

#omfatta

#inkludera "log.h"

int *rlog_1(char **arg)

/*Returvärdet måste definieras som statiskt*/

statiskt int resultat;

int fd; /*Loggfilsbeskrivning*/

/*0öppna loggfilen (skapa den om den inte finns), returnera en felkod om den misslyckas resultat == 1.*/

if ((fd=öppen("./server .log",

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

len = strlen(*arg);

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

return(&result); /*Returnera resultatet - adressresultatet*/

Klientstubben tar argumentet som skickas till fjärrproceduren, gör nödvändiga omvandlingar, utfärdar en begäran till portmap(1M)-servern, kommunicerar med fjärrprocedurservern och skickar slutligen returvärdet till klienten. För klienten reduceras att ringa en fjärrprocedur till att ringa en stubb och skiljer sig inte från ett vanligt lokalsamtal.

klient.c

#omfatta

#inkludera "log.h"

main(int argc, char *argv)

char *server, *mystring, *clnttime;

if (argc != 2) (

fprintf(stderr, "Samtalsformat: %s värdadress\n",

/*Ta hand om klienten. Vid misslyckande kommer vi att informera dig om

oförmåga att upprätta anslutning till servern*/

if ((c1 = clnt_create (server,

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

clnt_pcreateerror(server);

/*Tilldela en buffert för strängen*/

mystring = (char*)malloc(100);

/*Bestämma tidpunkten för händelsen*/

bintime = tid((tid_t *) NULL);

clnttime = ctime(&bintime);

sprintf(mystring, "%s - Klient startade", clnttime);

/*Vi skickar ett meddelande för loggen - den tidpunkt då klienten började arbeta. I händelse av fel kommer vi att rapportera felet */

if ((resultat = rlog_l(&mystring, cl)) == NULL) (

fprintf(stderr, "fel2\n");

clnt_perror(cl, server);

/*I händelse av fel på fjärrdatorn, rapportera ett fel*/

om (*resultat !=0)

fprintf(stderr, "Fel vid skrivning till logg\n");

/*0frigör handtaget*/

cint förstöra(cl);

Log_clnt.c-klientstubben kompileras med client.c-modulen för att producera en klientkörbar fil.

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

Log_svc.c-serverstubben och log.c-proceduren kompileras för att producera en körbar server.

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

Nu på någon värd server.nowhere.ru måste du starta serverprocessen:

Efter det, när rlog-klienten startas på en annan dator, kommer servern att lägga till lämplig post i loggfilen.

Schemat för RPC-drift i detta fall visas i fig. 1. Moduler interagerar enligt följande:

1. När en serverprocess startar skapar den en UDP-socket och binder alla lokala portar till den socket. Därefter anropar servern biblioteksfunktionen svc_register(3N) för att registrera programnummer och versioner. För att göra detta anropar funktionen portmap(IM)-processen och skickar de nödvändiga värdena. Portmap(IM)-servern startar vanligtvis när systemet initieras och binder till någon välkänd port. Nu vet portmap(3N) portnumret för vårt program och version. Servern väntar på att få en förfrågan. Observera att alla de beskrivna åtgärderna utförs av serverstubben som skapats av rpcgen(IM)-kompilatorn.

2. När rlog-programmet startar är det första det gör att anropa biblioteksfunktionen clnt_create(3N) och ge den adressen till fjärrsystemet, programmet och versionsnumren samt transportprotokollet. Funktionen skickar en begäran till portmap(IM)-servern för fjärrsystemet server.nowhere.m och får fjärrportnumret för loggservern.

3. Klienten anropar proceduren rlog_1() definierad i klientstubben och överför kontrollen till stubben. Det i sin tur bildar en begäran (genom att konvertera argumenten till XDR-format) i form av ett UDP-paket och skickar det till fjärrporten som tas emot från portmap(IM)-servern. Den väntar sedan på svar under en tid och, om den inte mottas, skickar den om begäran. Under gynnsamma omständigheter accepteras begäran av loggerservern (serverstubmodul). Stubben bestämmer vilken funktion som anropades (med procedurnummer) och anropar funktionen rlog_1() för log.c-modulen. Efter att ha återfört kontrollen tillbaka till stubben, konverterar stubben värdet som returneras av funktionen rlog_1 () till XDR-format och genererar ett svar även i form av ett UDP-paket. Efter att ha mottagit svaret extraherar klientstubben det returnerade värdet, konverterar det och returnerar det till klientens huvudprogram.




Program som kommunicerar över ett nätverk behöver en kommunikationsmekanism. På den lägre nivån, vid ankomsten av paket, sänds en signal, som bearbetas av nätverkssignalbehandlingsprogrammet. På den översta nivån fungerar mötesmekanismen (rendezvous) som används i Ada-språket. NFS använder en RPC-mekanism (Remote Procedure Call) där klienten kommunicerar med servern (se figur 1). Enligt denna process anropar klienten först en procedur som skickar en begäran till servern. Vid ankomsten av ett paket med en begäran anropar servern proceduren för att öppna den, utför den begärda tjänsten, skickar ett svar och kontrollen returneras till klienten.

RPC-gränssnittet kan ses som att det består av tre lager:

  1. Den översta nivån är helt "transparent". Ett program på denna nivå kan till exempel innehålla ett anrop till proceduren rnusers(), som returnerar antalet användare på fjärrdatorn. Du behöver inte veta om att använda RPC-mekanismen så länge du ringer i programmet.
  2. Mellanskiktet är för de vanligaste applikationerna. RPC-anrop på denna nivå hanteras av subrutinerna registerrpc() och callrpc(): registerrpc() får systemomfattande kod och callrpc() utför ett fjärrproceduranrop. Anropet till rnusers() implementeras med dessa två subrutiner.
  3. Den lägre nivån används för mer komplexa uppgifter som ändrar standardvärdena till procedurens parametervärden. På den här nivån kan du explicit manipulera uttagen som används för att skicka RPC-meddelanden.

Som en allmän regel bör du använda den övre nivån och undvika att använda de lägre nivåerna om det inte är absolut nödvändigt.

Även om vi bara täcker C-gränssnittet i denna handledning, kan fjärranrop göras från vilket språk som helst. Funktionen av RPC-mekanismen för att organisera kommunikation mellan processer på olika maskiner skiljer sig inte från dess funktion på samma maskin.

RPC (Remote Procedure Call, Remote Procedure Call Service) är ett gränssnitt mellan fjärranvändare och vissa värdprogram som körs på begäran av dessa användare. En värds RPC-tjänst tillhandahåller vanligtvis en uppsättning program till klienter. Vart och ett av dessa program består i sin tur av en eller flera fjärrprocedurer. Till exempel kan en fjärransluten NFS-tjänst som är byggd på RPC-anrop bestå av endast två program: till exempel interagerar ett program med användargränssnitt på hög nivå och det andra med I/O-funktioner på låg nivå.

Det finns två parter involverade i varje fjärrproceduranrop: den aktiva klienten, som skickar en proceduranropsbegäran till servern, och servern som skickar ett svar tillbaka till klienten.

Notera. Tänk på att termerna "klient" och "server" i det här fallet hänvisar till en specifik transaktion. En viss värd eller programvara (process eller program) kan fungera som både klient och server. Till exempel kan ett program som tillhandahåller en fjärrprocedurtjänst också vara en klient som arbetar med ett nätverksfilsystem.

RPC-protokollet är byggt på en fjärrproceduranropsmodell liknande den för lokala proceduranrop. När du anropar en lokal procedur placerar du argumenten på en specifik plats i minnet, på stacken eller i miljövariabler och överför kontrollen över processen till en specifik adress. När du är klar läser du resultaten på en specifik adress och fortsätter med din process.

När det gäller att arbeta med en fjärrprocedur är den största skillnaden att fjärrfunktionsanropet betjänas av två processer: klientprocessen och serverprocessen.

Klientprocessen skickar ett meddelande till servern, som inkluderar parametrarna för den anropade proceduren, och väntar på ett svarsmeddelande med resultatet av dess arbete. När ett svar tas emot läses resultatet och processen fortsätter. På serversidan är samtalshanterarprocessen i vänteläge, och när ett meddelande kommer, läser den procedurens parametrar, exekverar den, skickar ett svar och blir i vänteläge för nästa samtal.

RPC-protokollet ställer inga krav på ytterligare kommunikationer mellan processer och kräver inte synkronisering av de utförda funktionerna, d.v.s. samtal kan vara asynkrona och ömsesidigt oberoende, så att klienten kan utföra andra procedurer medan de väntar på ett svar. RPC-servern kan tilldela en separat process eller virtuell maskin för varje funktion, därför kan den, utan att vänta på att de tidigare förfrågningarna ska avslutas, omedelbart acceptera nästa.

Det finns dock flera viktiga skillnader mellan lokala och fjärranrop:

  1. Fel vid bearbetning. Klienten bör i alla fall meddelas om fel som uppstår vid fjärranrop på servern eller på nätverket.
  2. Globala variabler. Eftersom servern inte har tillgång till klientens adressutrymme kan fjärranrop inte använda dolda parametrar som globala variabler.
  3. Prestanda. Exekveringshastigheten för fjärrprocedurer är som regel en eller två storleksordningar lägre än exekveringshastigheten för liknande lokala procedurer.
  4. Autentisering. Eftersom fjärranrop sker över nätverket måste klientautentiseringsmekanismer användas.

Protokollkonstruktionsprinciper.

RPC-protokollet kan använda flera olika transportprotokoll. RPC-protokollets ansvar är endast att tillhandahålla standarder och tolka meddelandeöverföring. Tillförlitligheten och tillförlitligheten för meddelandeöverföring tillhandahålls helt och hållet av transportskiktet.

RPC kan dock styra valet och vissa funktioner i transportprotokollet. Som ett exempel på interaktion mellan RPC och ett transportprotokoll, låt oss överväga proceduren för att tilldela en RPC-port för en applikationsprocess genom RPC - Portmapper.

Denna funktion tilldelar dynamiskt (på begäran) en specifik port till en RPC-anslutning. Portmapper-funktionen används ganska ofta, eftersom uppsättningen av transportportar reserverade för RPC är begränsad, och antalet processer som potentiellt kan köras samtidigt är mycket högt. Portmapper, till exempel, kallas när man väljer portar för kommunikation mellan klienten och servern i NFS-systemet.

Portmapper-tjänsten använder RPC broadcast-meddelandemekanismen på en specifik port - III. På den här porten skickar klienten ett utsändningsmeddelande för portbegäran för en specifik RPC-tjänst. Portmapper-tjänsten behandlar meddelandet, bestämmer adressen till den lokala RPC-tjänsten och skickar ett svar tillbaka till klienten. RPC Portmapper-tjänsten kan fungera med både TCP- och UDP-protokoll.

RPC kan arbeta med olika transportprotokoll, men duplicerar aldrig deras funktioner, d.v.s. om RPC fungerar ovanpå TCP tilldelas alla bekymmer om RPC-anslutningens tillförlitlighet och tillförlitlighet till TCP. Men om RPC är installerat över UDP kan det ge ytterligare inbyggda funktioner för att säkerställa meddelandeleverans.

Notera.

Applikationsuppgifter kan betrakta RPC-protokollet som en specifik procedur för att anropa en funktion över ett JSR-nätverk (Jump Subroutine Instruction).

För att RPC-protokollet ska fungera måste följande villkor vara uppfyllda:

  1. Unik identifiering av alla fjärranropade procedurer på en given värd. RPC-begäranden innehåller tre identifierarfält - numret på fjärrprogrammet (tjänsten), versionsnumret för fjärrprogrammet och numret på fjärrproceduren för det angivna programmet. Programnumret tilldelas av tillverkaren av tjänsten, procedurnumret indikerar den specifika funktionen för denna tjänst
  2. Identifiering av RPC-protokollets version. RPC-meddelanden innehåller ett RPC-protokollversionsfält. Den används för att koordinera formaten för överförda parametrar när klienten arbetar med olika versioner av RPC.
  3. Tillhandahåller mekanismer för att autentisera klienten till servern. RPC-protokollet tillhandahåller en procedur för att autentisera klienten i tjänsten, och, om nödvändigt, med varje begäran eller skicka ett svar till klienten. Dessutom tillåter RPC olika ytterligare säkerhetsmekanismer att användas.

RPC kan använda fyra typer av autentiseringsmekanismer:

  • AUTH_NULL - ingen autentisering
  • AUTH_UNIX - UNIX standardautentisering
  • AUTH_SHORT - UNIX standardautentisering med egen kodningsstruktur
  • AUTH_DES - DES-autentisering
  1. Identifiering av svarsmeddelanden på motsvarande förfrågningar. RPC-svarsmeddelanden innehåller begäran-ID från vilket de byggdes. Detta ID kan kallas transaktions-ID för RPC-anropet. Denna mekanism är särskilt nödvändig när man arbetar i asynkront läge och när man kör en sekvens av flera RPC-anrop.
  2. Identifiering av protokollfel. Alla nätverks- eller serverfel har unika identifierare, med vilka var och en av deltagarna i anslutningen kan fastställa orsaken till felet.

Protokollmeddelandestrukturer

När RPC-meddelanden sänds över ett transportprotokoll kan flera RPC-meddelanden finnas inom ett enda transportpaket. För att separera ett meddelande från ett annat används en postmarkör (RM - Record Marker). Varje RPC-meddelande är "taggat" med exakt en RM.

Ett RPC-meddelande kan bestå av flera fragment. Varje fragment består av fyra rubrikbyte och (från 0 till 2**31-1) data. Den första biten i rubriken indikerar om det givna fragmentet är det sista, och de återstående 31 bitarna indikerar längden på datapaketet.

RPC:s struktur beskrivs formellt på språket för beskrivning och representation av dataformat - XDR med tillägg angående beskrivning av procedurer. Man skulle till och med kunna säga att RPC-beskrivningsspråket är en förlängning av XDR, kompletterat med arbete med procedurer.

Strukturen för ett RPC-paket ser ut så här:


Svarsstrukturen (reply_body) kan innehålla antingen en struktur som skickas i händelse av ett fel (i vilket fall den innehåller felkoden), eller en struktur som framgångsrikt bearbetade begäran (i vilket fall den innehåller de returnerade data).

Programmeringsgränssnitt på hög nivå.

Användningen av subrutiner i ett program är det traditionella sättet att strukturera en uppgift, för att göra den tydligare. De vanligaste rutinerna samlas i bibliotek där de kan användas av olika program. I det här fallet talar vi om ett lokalt (lokalt) samtal, dvs både det anropande och det anropade objektet fungerar inom samma program på samma dator.

I ett fjärrsamtal startar en process som körs på en dator en process på fjärrdatorn (det vill säga den kör faktiskt procedurkoden på fjärrdatorn). Uppenbarligen skiljer sig ett fjärrproceduranrop avsevärt från ett traditionellt lokalt, men ur programmerarens synvinkel finns det praktiskt taget inga sådana skillnader, dvs. fjärrprocedurens anropsarkitektur tillåter dig att simulera ett lokalt samtal.

Men om, i fallet med ett lokalt samtal, programmet skickar parametrar till den anropade proceduren och tar emot resultatet av arbetet genom stacken eller delade minnesområdena, då i fallet med ett fjärrsamtal, förvandlas överföring av parametrar till att skicka en begäran över nätverket, och resultatet av arbetet finns i det inkommande svaret.

Detta tillvägagångssätt är en möjlig grund för att skapa distribuerade applikationer, och även om många moderna system inte använder denna mekanism, finns de grundläggande begreppen och termerna i många fall kvar. När vi beskriver RPC-mekanismen kommer vi traditionellt att referera till anropsprocessen som klienten och fjärrprocessen som implementerar proceduren som servern.

Ett fjärranrop innehåller följande steg:

  1. Klientprogrammet gör ett lokalt anrop till en procedur som kallas stubb. Samtidigt "verkar" det för klienten att den, genom att anropa stubben, faktiskt anropar serverproceduren. Faktum är att klienten skickar de nödvändiga parametrarna till stubben och den returnerar resultatet. Situationen är dock inte riktigt som klienten föreställer sig. Stubbens uppgift är att acceptera argument avsedda för fjärrproceduren, kanske konvertera dem till något standardformat och bilda en nätverksbegäran. Att packa argument och göra en nätverksbegäran kallas för rangering.
  2. Nätverksbegäran skickas över nätverket till fjärrsystemet. För att göra detta använder stubben lämpliga anrop, såsom de som diskuterats i tidigare avsnitt. Observera att olika transportprotokoll kan användas i detta fall, och inte bara TCP/IP-familjerna.
  3. På fjärrvärden sker allt i omvänd ordning. Serverstubben väntar på en förfrågan och, när den tas emot, hämtar parametrar - procedurens anropsargument. Extraktion (unmarshalling) kan innefatta nödvändiga transformationer (till exempel omordning av bytes).
  4. Stubben gör ett anrop till den verkliga serverproceduren till vilken klientens förfrågan är adresserad och skickar den mottagna argumenten över nätverket.
  5. Efter att ha utfört proceduren återgår kontrollen till serverstubben och skickar de nödvändiga parametrarna till den. Liksom klientstubben; serverstubben konverterar värdena som returneras av proceduren för att bilda ett nätverkssvarsmeddelande som skickas över nätverket till systemet från vilket förfrågan kom.
  6. Operativsystemet skickar det mottagna meddelandet till klientstubben, som efter den nödvändiga transformationen skickar värdena (som är de värden som returneras av fjärrproceduren) till klienten, som tolkar detta som en normal retur från procedur.

Från klientens synvinkel ringer han alltså ett förfarande på distans, precis som han skulle göra för ett lokalt. Detsamma kan sägas om servern: proceduren anropas på vanligt sätt, något objekt (serverstub) anropar den lokala proceduren och tar emot värdena som returneras av det. Klienten behandlar stubben som en anropsbar serverprocedur, och servern tar sin egen stubb som klient.

Således utgör stubbar kärnan i RPC-systemet, ansvarig för alla aspekter av att generera och skicka meddelanden mellan klienten och fjärrservern (procedur), även om både klient och server anser att samtalen ska göras lokalt. Detta är huvudkonceptet för RPC - att helt dölja den distribuerade (nätverks)naturen för interaktionen i stubbkoden. Fördelarna med detta tillvägagångssätt är uppenbara: både klienten och servern är oberoende av nätverksimplementeringen, de arbetar båda inom en distribuerad virtuell maskin och proceduranropen har ett standardgränssnitt.

Passerar parametrar

Att passera värdeparametrar är inte svårt. I det här fallet placerar klientstubben värdet på parametern i nätverksbegäran, kanske genom att utföra standardkonverteringar (till exempel ändra endianness). Situationen är mycket mer komplicerad med att skicka pekare när parametern är adressen till data och inte deras värde. Att skicka en adress i begäran är meningslöst eftersom fjärrproceduren körs i ett helt annat adressutrymme. Den enklaste lösningen som används i RPC är att förhindra att klienter skickar andra parametrar än efter värde, även om detta verkligen medför allvarliga begränsningar.

Bindande

Innan en klient kan anropa en fjärrprocedur måste den vara associerad med ett fjärrsystem som har den nödvändiga servern. Således är uppgiften att binda uppdelad i två:

  1. Hitta en fjärrvärd med en önskad server
  2. Att hitta den nödvändiga serverprocessen på en given värd

Olika metoder kan användas för att hitta en värd. Ett möjligt alternativ är att skapa någon form av centraliserad katalog där värdar tillkännager sina servrar, och där klienten, om så önskas, kan välja värd och adress för proceduren som passar honom.

Varje RPC-procedur identifieras unikt av ett program- och procedurnummer. Programnumret definierar en grupp av fjärrprocedurer, som var och en har sitt eget nummer. Varje program tilldelas också ett versionsnummer, så om du gör mindre ändringar i programmet (till exempel lägger till en procedur) behöver du inte ändra dess nummer. Vanligtvis implementeras flera funktionellt likartade procedurer i en programmodul, som, när den startas, blir servern för dessa procedurer, och som identifieras av programnumret.

Sålunda, när en klient vill anropa en fjärrprocedur, måste den känna till programmet, versionen och procedurnumren som tillhandahåller den erforderliga tjänsten.

För att skicka en begäran måste klienten också känna till värdens nätverksadress och portnumret som är associerat med serverprogrammet som tillhandahåller de nödvändiga procedurerna. Detta görs med hjälp av portmap(IM)-demonen (kallad rpcbind(IM) på vissa system). Demonen körs på en värd som tillhandahåller en fjärrprocedurtjänst och använder ett välkänt portnummer. När en serverprocess initieras, registrerar den dess procedurer och portnummer i portmap(IM). Nu, när klienten behöver veta portnumret för att anropa en viss procedur, skickar den en begäran till portmap(IM)-servern, som i sin tur antingen returnerar portnumret eller vidarebefordrar begäran direkt till fjärrprocedurservern och returnerar ett svar till klienten när det körs. I alla fall, om den nödvändiga proceduren finns, får klienten portnumret för proceduren från portmap(IM)-servern och kan göra ytterligare förfrågningar direkt till denna port.

Hantering av speciella situationer (undantag)

Att hantera undantag när man anropar lokala rutiner är inte något större problem. UNIX tillhandahåller hantering av processfel såsom division med noll, åtkomst till ett ogiltigt minnesområde etc. Vid ett fjärranrop ökar sannolikheten för felsituationer. Fel relaterade till att till exempel ta emot ett felaktigt nätverksmeddelande har lagts till på server- och stubbfel.

Till exempel, när man använder UDP som transportprotokoll, sänds meddelanden om efter en viss timeout. Ett fel returneras till klienten om det efter ett visst antal försök inte har mottagits något svar från servern. I det fall då TCP-protokollet används, returneras ett fel till klienten om servern avslutade TCP-anslutningen.

Ring semantik

Att anropa en lokal procedur leder otvetydigt till dess exekvering, varefter kontrollen återgår till huvudprogrammet. Situationen är annorlunda när man anropar en fjärrprocedur. Det är omöjligt att avgöra exakt när proceduren kommer att utföras, om den kommer att utföras överhuvudtaget och i så fall hur många gånger? Till exempel, om begäran tas emot av fjärrsystemet efter att serverprogrammet kraschar, kommer proceduren inte att utföras alls. Om klienten inte tar emot ett svar efter en viss tidsperiod (timeout), skickar om begäran kan en situation uppstå när svaret redan har sänts över nätverket och den upprepade begäran accepteras igen för behandling av fjärrproceduren . I det här fallet kommer proceduren att utföras flera gånger.

Sålunda kan exekveringen av en fjärrprocedur karakteriseras av följande semantik:

  • En och bara en gång. Detta beteende (i vissa fall det mest önskvärda) är svårt att kräva på grund av möjliga serverkrascher.
  • Maxtider. Detta innebär att proceduren antingen inte utfördes alls eller bara utfördes en gång. Ett liknande påstående kan göras när man får ett fel istället för ett normalt svar.
  • Åtminstone en gång. Proceduren utfördes förmodligen en gång, men mer är möjligt. För normal drift i en sådan situation måste fjärrproceduren ha egenskapen idempotent (från den engelska idemponenten). Den här egenskapen har en procedur vars upprepad körning inte orsakar kumulativa ändringar. Till exempel är det idempotent att läsa en fil, men att lägga till text i en fil är det inte.

Datarepresentation

När klienten och servern körs på samma system på samma dator finns det inga datainkompatibilitetsproblem. Både för klienten och för servern presenteras data i binär form på samma sätt. I fallet med ett fjärranrop kompliceras saken av att klienten och servern kan köras på system med olika arkitekturer som har olika datarepresentationer (till exempel representationen av ett flyttalsvärde, byteordning, etc.)

De flesta implementeringar av RPC-systemet definierar några standarddatarepresentationer till vilka alla värden som skickas i förfrågningar och svar måste konverteras.

Datarepresentationsformatet i Sun Microsystems RPC är till exempel följande:

  1. Byte Order - Största sist
  2. Representerar flyttalsvärden - IEEE
  3. Karaktärsrepresentation - ASCII

Netto

RPC-systemet intar i sin funktionalitet en mellanposition mellan applikationsskiktet och transportskiktet. I enlighet med OSI-modellen motsvarar denna bestämmelse presentations- och sessionslagren. Således är RPC teoretiskt oberoende av implementeringen av nätverket, i synnerhet av nätverksprotokollen för transportskiktet.

Programvaruimplementationer av systemet stöder som regel ett eller två protokoll. Till exempel stöder Sun Microsystems RPC-system meddelandeöverföring med TCP- och UDP-protokollen. Valet av ett eller annat protokoll beror på applikationens krav. Valet av UDP-protokoll är motiverat för applikationer med följande egenskaper:

  • Kallade procedurer är idempotenta
  • Storleken på de godkända argumenten och det returnerade resultatet är mindre än storleken på UDP-paketet - 8 KB.
  • Servern ger arbete med flera hundra klienter. Eftersom servern tvingas upprätthålla en anslutning med var och en av de aktiva klienterna när den arbetar med TCP-protokoll, tar detta upp en betydande del av dess resurser. UDP-protokollet är mindre resurskrävande i detta avseende.

Å andra sidan möjliggör TCP effektiv drift av applikationer med följande egenskaper:

  • Applikationen kräver ett tillförlitligt överföringsprotokoll
  • Kallade procedurer är icke-komponenter
  • Storleken på argumenten eller returresultatet överstiger 8 KB

Valet av protokoll förblir vanligtvis hos klienten, och systemet organiserar bildandet och överföringen av meddelanden på olika sätt. Så när du använder TCP-protokollet, för vilket de överförda data är en ström av byte, är det nödvändigt att separera meddelanden från varandra. För att göra detta används till exempel postmarkeringsprotokollet som beskrivs i RFC1057 "RPC: Remote Procedure Call Protocol specification version 2", där ett 32-bitars heltal placeras i början av varje meddelande, som anger storleken på meddelandet i byte.

Situationen är annorlunda med samtalets semantik. Till exempel, om RPC utförs med hjälp av ett opålitligt transportprotokoll (UDP), återsänder systemet meddelandet med korta intervall (timeouts). Om klientapplikationen inte får något svar, är det säkert att säga att proceduren har utförts noll eller fler gånger. Om ett svar inkommit kan ansökan dra slutsatsen att ingreppet utförts minst en gång. Med Trusted Transport Protocol (TCP), om ett svar tas emot, kan man säga att proceduren utfördes en gång. Om svaret inte tas emot är det omöjligt att definitivt säga att proceduren inte utfördes3.

Hur det fungerar?

I huvudsak är själva RPC-systemet inbyggt i klientprogrammet och serverprogrammet. Den goda nyheten är att när du utvecklar distribuerade applikationer behöver du inte fördjupa dig i detaljerna i RPC-protokollet eller programmeddelandebehandling. Systemet förutsätter att det finns en lämplig utvecklingsmiljö, vilket avsevärt förenklar livet för skaparna av applikationsprogramvara. En av nyckelpunkterna i RPC är att utvecklingen av en distribuerad applikation börjar med definitionen av ett objektgränssnitt - en formell beskrivning av serverns funktioner, gjord på ett speciellt språk. Baserat på detta gränssnitt genereras sedan klient- och serverstubbar automatiskt. Det enda du kan göra efter det är att skriva själva procedurkoden.

Som ett exempel, överväg RPC från Sun Microsystems. Systemet består av tre huvuddelar:

  • rpcgen(1) är en RPC-kompilator som genererar klient- och serverstubbar som C-program baserat på beskrivningen av fjärrprocedurens gränssnitt.
  • XDR-biblioteket (eXternal Data Representation), som innehåller funktioner för att konvertera olika typer av data till en maskinoberoende form, vilket möjliggör utbyte av information mellan heterogena system.
  • Ett bibliotek med moduler som säkerställer driften av systemet som helhet.

Låt oss överväga ett exempel på den enklaste distribuerade händelseloggningsapplikationen. Klienten anropar vid start en fjärrprocedur för att skriva ett meddelande till fjärrdatorns loggfil.

För att göra detta måste du skapa minst tre filer: specifikationen för log.x-fjärrprocedurgränssnitten (i gränssnittsbeskrivningsspråket), den faktiska texten för log.c-fjärrprocedurerna och texten för klientens huvud program main () - client.c (på C-språket).

rpcgen(l)-kompilatorn genererar tre filer baserat på log.x-specifikationen: texten för klient- och serverstubbarna på C-språket (log clnt.c och log svc.c) och beskrivningsfilen log.h som används av båda stubbarna .

Så låt oss titta på källkoden för programmen.

Den här filen specificerar registreringsparametrarna för fjärrproceduren - program-, versions- och procedurnummer, och definierar även anropsgränssnittet - inmatningsargument och returvärden. Sålunda definieras RLOG-proceduren och tar som argument en sträng (som kommer att skrivas till loggen), och returvärdet indikerar som standard framgång eller misslyckande för den beställda operationen.


program LOG_PROG( version LOG_VER( int RLOG (sträng) = 1; ) = 1; ) = 0x31234567;

rpcgen(l)-kompilatorn skapar en rubrikfil log.h, där i synnerhet procedurerna är definierade:


Låt oss titta närmare på den här filen. Kompilatorn översätter RLOG-namnet som definieras i gränssnittets definitionsfil till rlog_1, ersätter versaler med gemener och lägger till programmets versionsnummer med ett understreck. Returtypen har ändrats från int till int *. Detta är regeln - RPC låter dig skicka och ta emot endast adresserna till parametrarna som deklareras i beskrivningen av gränssnittet. Samma regel gäller för strängen som skickas som ett argument. Även om filen print.h inte antyder detta, skickas faktiskt adressen till raden också som ett argument till funktionen rlog_l ().

Förutom header-filen genererar rpcgen(l)-kompilatorn klientstub- och serverstubmoduler. I huvudsak innehåller texten i dessa filer all fjärranropskod.

Serverstubben är värdprogrammet som hanterar all nätverksinteraktion med klienten (mer exakt, med dess stubb). För att utföra operationen gör serverstubben ett lokalt funktionsanrop, vars text måste skrivas:


Klientstubben tar argumentet som skickas till fjärrproceduren, gör nödvändiga omvandlingar, utfärdar en begäran till portmap(1M)-servern, kommunicerar med fjärrprocedurservern och skickar slutligen returvärdet till klienten. För klienten reduceras att ringa en fjärrprocedur till att ringa en stubb och skiljer sig inte från ett vanligt lokalsamtal.

klient.c


#omfatta #omfatta"log.h" huvud(int argc, röding*argv) ( KLIENT *cl; röding*server, *mystring, *clnttime; time_tbintime; int*resultat; om(argc != 2) ( fprintf(stderr, "Anropsformat: %s HostAddress\n", argv ); avsluta (1) ; ) server = argv ; /*Ta hand om klienten. I händelse av fel kommer vi att rapportera att det är omöjligt att upprätta en anslutning till servern */ om((c1 = clnt_create (server, LOG_PROG, LOG_VER, "udp")) == NULL) ( clnt_pcreateerror (server); avsluta (2); ) /*Tilldela en buffert för strängen*/ mystring = ( röding*) malloc(100); /*Bestämma tidpunkten för händelsen*/ bintime = tid((tid_t *) NULL); clnttime = ctime(&bintime); sprintf(mystring, "%s - Klient startade", clnttime); /*Vi skickar ett meddelande för loggen - den tidpunkt då klienten började arbeta. I händelse av fel kommer vi att rapportera felet */ om((resultat = rlog_l(&mystring, cl)) == NULL) ( fprintf(stderr, "error2\n"); clnt_perror(cl, server); exit(3); ) /*I händelse av fel på fjärrdatorn, rapportera ett fel*/ om(*resultat !=0) fprintf(stderr, "Fel vid skrivning till logg\n"); /*0frigör handtaget*/ cint förstöra(cl); exit(0); )

Log_clnt.c-klientstubben kompileras med client.c-modulen för att producera en klientkörbar fil.


Nu på någon värd server.nowhere.ru måste du starta serverprocessen:


$ logger

Efter det, när rlog-klienten startas på en annan dator, kommer servern att lägga till lämplig post i loggfilen.

Schemat för RPC-drift i detta fall visas i fig. 1. Moduler interagerar enligt följande:

  1. När en serverprocess startar skapar den en UDP-socket och binder alla lokala portar till den socket. Därefter anropar servern biblioteksfunktionen svc_register(3N) för att registrera programnummer och versioner. För att göra detta anropar funktionen portmap(IM)-processen och skickar de nödvändiga värdena. Portmap(IM)-servern startar vanligtvis när systemet initieras och binder till någon välkänd port. Nu vet portmap(3N) portnumret för vårt program och version. Servern väntar på att få en förfrågan. Observera att alla de beskrivna åtgärderna utförs av serverstubben som skapats av rpcgen(IM)-kompilatorn.
  2. När rlog-programmet startar är det första det gör att anropa biblioteksfunktionen clnt_create(3N) och ge den adressen till fjärrsystemet, program- och versionsnumren och transportprotokollet. Funktionen skickar en begäran till portmap(IM)-servern för fjärrsystemet server.nowhere.m och får fjärrportnumret för loggservern.
  3. Klienten anropar proceduren rlog_1() som definieras i klientstubben och överför kontrollen till stubben. Det i sin tur bildar en begäran (genom att konvertera argumenten till XDR-format) i form av ett UDP-paket och skickar det till fjärrporten som tas emot från portmap(IM)-servern. Den väntar sedan på svar under en tid och, om den inte mottas, skickar den om begäran. Under gynnsamma omständigheter accepteras begäran av loggerservern (serverstubmodul). Stubben bestämmer vilken funktion som anropades (med procedurnummer) och anropar funktionen rlog_1() för log.c-modulen. Efter att ha återfört kontrollen tillbaka till stubben, konverterar stubben värdet som returneras av funktionen rlog_1 () till XDR-format och genererar ett svar även i form av ett UDP-paket. Efter att ha mottagit svaret extraherar klientstubben det returnerade värdet, konverterar det och returnerar det till klientens huvudprogram.






2022 gtavrl.ru.