450 likes | 651 Views
Sistemsko programiranje. VIII. poglavlje Međuprocesna komunikacija. Ciljevi. Nakon svladavanja ovog poglavlja trebali bi znati : Opisati Windows mehanizme za međuprocesnu komunikaciju Opisati različite mogućnosti anonimnih pipa, imenovanih pipa i mailslotova
E N D
Sistemsko programiranje VIII. poglavlje Međuprocesna komunikacija
Ciljevi Nakon svladavanja ovog poglavlja trebali bi znati: • Opisati Windows mehanizme za međuprocesnu komunikaciju • Opisati različite mogućnosti anonimnih pipa, imenovanih pipa i mailslotova • Koristiti načine Windows međuprocesne komunikacije za razvoj aplikacija sa zajedničkim procesiranjem
Alternative međuprocesne komunikacije • Windows objekti bajtovno orijentirani ili preko poruka • Pipe (anonimne i imenovane) • Mailslotovi • Mrežni rad • Windows socketi (standardno sučelje za TCP/IP) • Udaljeni pozivi procedura (Remote Procedure Calls - RPC) • Objektno-orijentirano • OLE; COM (Component Object Model) • Drugi načini • Dijeljena memorija preko memorijski mapiranih datoteka • Datoteke
Pregled (1/2) • Međuprocesna komunikacija (Interprocess Communication, IPC) je omogućena s bajtno-baziranim ili bazirano na porukama “pipama” • Anonimne (bezimene) pipe • Dobra stvar za preusmjeravanje izlaza jednog na ulaz drugog programa • Anonimne pipe su orijentirane na “streamove” (tok podataka)
Pregled (2/2) • Imenovane pipe • Dopuštaju mrežnu komunikaciju • Više handle-ova na istu pipu • Transakcijski orijentirane funkcije za imenovane pipe • Idealne za kreiranje jednostavnih klijent/server sistema • Imenovane pipe su orijentirane na poruke • Mailslotovi omogućavaju jedan-na-više odašiljanje poruka (message broadcasting)
Dnevni red • 1. dio Anonimne pipe • 2. dio Imenovane pipe • 3. dio Mailslotovi
1. dio Anonimne pipe
Anonimne pipe • Dopuštaju jednosmjernu (half-duplex), bazirano na znakovima (character, byte) IPC • Dva handle-a: handle za čitanje i handle za pisanje • Određuje se predviđena veličina buffera za pipu • Vrlo često želimo da pipe budu nasljedivi handle-ovi
IPC koristeći anonimnu pipu CreatePipe (&hRead, &hWrite) StartUp.hStdOutput = hWrite CreateProcess ("Program1") StartUp.hStdInput = hRead CreateProcess ("Program2") WaitForMultipleObjects pipa Program1 Program2 hIn = CreateFile (argv [1]) while ( ) { ReadFile (hIn) WriteFile (hWrite) } ExitProcess (0) hOut = CreateFile (argv [2]) while ( ) { ReadFile (hRead) } WriteFile (hOut) Pipa
Upravljanje anonimnim pipama (1/2) BOOL CreatePipe (PHANDLE phRead, PHANDLE phWrite, LPSECURITY_ATTRIBUTES lpsa, DWORD cbPipe)
Upravljanje anonimnim pipama (2/2) • cbPipe • Veličina pipe u byte-ima; koristiti 0 za preddefiniranu vrijednost • phRead • Adresa od HANDLE-a • CreatePipe će postaviti *phRead • phWrite se koristi za handle za pisanje nove pipe • Čitanje blokova ako je pipa prazna; u suprotnom čitanje će prihvatiti onoliko byte-ova koliko ih ima u pipi, sve do broja određenog pozivom ReadFile • Pisanje u punu pipu će blokirati
2. dio Imenovane pipe
Imenovane pipe (1/2) • Dobar mehanizam za implementaciju aplikacija baziranih na IPC-u, uključujući ograničene mrežne klijent/server sisteme • Koristiti WinSockets za ozbiljniju mrežnu IPC • Koristiti imenovane pipe primarno za jedno-sistemsku IPC • Bazirano na porukama, tako da proces koji čita može pročitati poruke različite veličine, precizno kako ih šalje proces koji ih piše
Imenovane pipe (2/2) • Bidirekcionalno, tako da dva procesa mogu razmjenjivati poruke preko iste pipe • Mogu se kreirati višestruki, neovisni primjerci imenovane pipe • Više klijenata mogu komunicirati s jednim serverom koristeći istu pipu • Server može odgovoriti klijentima koristeći isti primjerak • Imenu pipe se može pristupiti sa sistema preko mreže
Do N klijenata Klijenti i server koji koriste imenovanu pipu Klijent 0 h = CreateFile (PipeName); while ( ) { WriteFile (h, &Request); ReadFile (h, &Response) /* Procesiraj odg. */ } CloseHandle (h); Server /* Kreiraj N primjeraka */ for (i = 0; i < N, i++) h [i] = CreateNamedPipe (PipeName, N); /* Odaberi svaki primjerak pipe, daj zahtjev, vrati odgovor */ i = 0; while ( ) { if PeekNamedPipe (h [i]) { ReadFile (h [i], &Request); /* Napravi odgovor */ WriteFile (h [i], &Response); } i = i++ % N; } Primjerak pipe 0 · · · · Klijent (N-1) h = CreateFile (PipeName); while ( ) { WriteFile (h, &Request); ReadFile (h, &Response) /* Procesiraj odg. */ } CloseHandle (h); Primjerak pipe N-1
Korištenje imenovanih pipa (1/2) • Prikazani model ima dvije značajne mane: • Server “odabire u krug” handle-ove imenovane pipe umjesto da čeka na konekciju ili na zahtjev. • Može procesirati samo jednog klijenta istovremeno. Ovo se može popraviti korištenjem više niti.
Korištenje imenovanih pipa (2/2) • CreateNamedPipe kreira prvi primjerak imenovane pipe i vraća handle • Proces koji kreira se tretira kao server • Klijenti, možda i na drugim sustavima, otvaraju pipu s pozivom CreateFile
Kreiranje imenovane pipe (1/5) HANDLE CreateNamedPipe (LPCTSTR lpszPipeName, DWORD fdwOpenMode, DWORD fdwPipeMode, DWORD nMaxInstances, DWORD cbOutBuf, DWORD cbInBuf, DWORD dwTimeOut, LPSECURITY_ATTRIBUTES lpsa) • lpszPipeName je ime pipe • Mora biti oblika \\.\pipe\[path]pipename • Ne može se kreirati pipa na udaljenom (drugom) stroju
Kreiranje imenovane pipe (2/5) • fdwOpenMode određuje jedan od načina: • PIPE_ACCESS_DUPLEX • Ekvivalentno GENERIC_READ | GENERIC_WRITE • PIPE_ACCESS_INBOUND — Tok podataka je samo od klijenta prema serveru • Ekvivalentno GENERIC_READ • PIPE_ACCESS_OUTBOUND • Način može također odrediti FILE_FLAG_WRITE_THROUGH (ne koristi se kod pipa s porukama) i FILE_FLAG_OVERLAPPED
Kreiranje imenovane pipe (3/5) • fdwPipeMode ima tri međusobno isključiva para zastavica koji pokazuju da li je pisanje bajtno orijentirano ili na poruke, da li je čitanje preko poruka ili blokova, i da li operacija čitanja blokira • PIPE_TYPE_BYTE i PIPE_TYPE_MESSAGE • Međusobno isključive • Pisanje niaz byte-ova ili poruka • Treba koristiti isti tip za sve primjerke pipe
Kreiranje imenovane pipe (4/5) • PIPE_READMODE_BYTE i PIPE_READMODE_MESSAGE • Čitanje niza byte-ova ili poruka • PIPE_READMODE_MESSAGE zahtjeva PIPE_TYPE_MESSAGE • PIPE_WAIT i PIPE_NOWAIT određuje da li će ReadFile blokirati ili ne • Koristiti PIPE_WAIT jer je to bolji načina za postizanje asinkronog I/O
Kreiranje imenovane pipe (5/5) • nMaxInstances — broj primjeraka pipe, što određuje broj simultanih klijenata • Odrediti uvijek istu vrijednost za svaki poziv CreateNamedPipe za određenu pipu • PIPE_UNLIMITED_INSTANCES dopušta OS-u da odredi broj mogućih sistemskih resursa • cbOutBuf i cbInBuf savjetuju OS za zahtjevanu veličinu buffer-a za ulazi i izlaz • dwTimeOut — predefinirani time-out period (u milisekundama) za WaitNamedPipe funkciju • lpsa je kao i u svim drugim “Create” funkcijama
Odabiranje BOOL PeekNamedPipe (HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer, LPDWORD lpcbRead, LPDWORD lpcbAvail, LPDWORD lpcbMessage) • Čita bez uništavanja byte-ove ili poruke u pipi • Ne blokira • Odmah vraća rezultat • Testirati *lpcbAvail kako bi odredili da li ima podataka u pipi
Konekcija klijenata na imenovane pipe • Klijent se može “konektirati” na imenovanu pipu koristeći CreateFile s imenom imenovane pipe • U više slučajeva, klijent i server su na istom stroju, i ime će biti oblika: \\.\pipe\[path]pipename • Ako je server na drugom stroju, ime će biti: \\servername\pipe\[path]pipename • Korištenje imena “.” kad je server na istom stroju, radije nego lokalno ime stroja (puno je brže)
Funkcije stanja imenovane pipe (1/2) • Dvije funkcije za dobivanje informacija o stanju pipe • GetNamedPipeHandleState vraća informaciju, za dani handle, o tome da li je pipa u blokirajućem ili u neblokirajućem stanju, da li je byte-no orijentirana ili na poruke, broj primjeraka pipe, itd. • SetNamedPipeHandleState dopušta nam da postavimo navedene atribute stanja
Funkcije stanja imenovane pipe (2/2) • Još jedna funkcija za dobivanje informacija o stanju • GetNamedPipeInfo određuje da li je handle za serverski primjerak ili za primjerak klijenta, veličinu buffera, itd.
Funkcije za rad s imenovanim pipama (1/7) • Kada imamo konekciju koja ima dugo trajanje, možemo kombinirati WriteFile, ReadFile sekvencu kod klijenta • Također postoje prednosti u izvedbi, jer konekcija nije potrebna (stalno je prisutna)
Funkcije za rad s imenovanim pipama (2/7) BOOL TransactNamedPipe (HANDLE hNamedPipe, LPVOID lpvWriteBuf, DWORD cbWriteBuf, LPVOID lpvReadBuf, DWORD cbReadBuf, LPDWORD lpcbRead, LPOVERLAPPED lpa) • Oba buffera i za ulaz i za izlaz su zadana • *lpcbRead — Duljina poruke
Funkcije za rad s imenovanim pipama (3/7) BOOL CallNamedPipe (LPCTSTR lpszPipeName, LPVOID lpvWriteBuf, DWORD cbWriteBuf, LPVOID lpvReadBuf, DWORD cbReadBuf, LPDWORD lpcbRead, DWORD dwTimeOut)
Funkcije za rad s imenovanim pipama (4/7) • Sinkronizirana: Create/Write/Read/Close konekcija “kratkog života” s klijentom • Smanjuje upotrebu primjerka ali uvećava broj konektiranja • Određen je time-out period za konekciju, u milisekundama ili: • NMPWAIT_NOWAIT • NMPWAIT_WAIT_FOREVER • NMPWAIT_USE_DEFAULT_WAIT
Funkcije za rad s imenovanim pipama (5/7) BOOL WaitNamedPipe (LPCTSTR lpszPipeName, DWORD dwTimeOut) • Klijent može čekati na primjerak imenovane pipe dok ne postane dostupan
Funkcije za rad s imenovanim pipama (6/7) BOOL ConnectNamedPipe (HANDLE hNamedPipe, LPOVERLAPPED lpo) BOOL DisconnectNamedPipe (HANDLE hNamedPipe) • S lpo postavljenim na NULL, ConnectNamedPipe će završiti čim server dobije konekciju s klijentom
Funkcije za rad s imenovanim pipama (7/7) • Normalno vraća vrijednost TRUE • Vraćena vrijednsot je FALSE ako je klijent spojen između serverovog poziva CreateNamedPipe i poziva ConnectNamedPipe • U tom slučaju, GetLastError vraća ERROR_PIPE_CONNECTED • Izvoditi ReadFile, WriteFile operacije između konekcije i završetka konekcije (disconnect)
Sigrunost imenovane pipe • Najvažnija sigurnosna prava kod imenovanih pipa su: • GENERIC_READ • GENERIC_WRITE • SYNCHRONIZE (omogućava niti da čeka na pipu) • Normalno dobivaju se odgovarajuća prava ovisno o pristupu (duplex, inbound, outbound) • Sva tri zahtjevaju SYNCHRONIZE
Klijent/server imenovane pipe koje koriste konekciju “kratkog života” Klijent Server CreateNamedPipe ConnectNamedPipe WaitNamedPipe CreateFile WriteFile ReadFile WriteFile DisconnectNamedPipe ReadFile CloseHandle
3. dio Mailslotovi
Mailslotovi (1/3) • Imaju imena, tako da ih nepovezani procesi mogu koristiti za komunikaciju • Mehanizmi za odašiljanje (broadcast) koji se ponašaju drugačije nego imenovane pipe • Jednosmjerno • Mogu imati više čitača i pisačaa, ali često se koriste na način “jedan-na-više” • Pisač (“klijent”) ne zna da li čitači (“serveri”) zaista primaju poruku
Mailslotovi (2/3) • Mogu biti locirani preko mrežne domene • Duljine poruka su ograničene • Svaki mailslot server (nemojte ih pomiješati s aplikacijskim serverima ili sa serverima imenovane pipe) kreira mailslot handle s funkcijom CreateMailslot • Server čeka da primi mailslot poruku s pozivom funkcije ReadFile • Klijent koji samo piše treba otvoriti mailslot s funkcijom CreateFile i pisati poruku s WriteFile
Mailslotovi (3/3) • Otvaranje neće uspjeti (ime nije pronađeno) ako nema čitača koji čekaju • Poruku klijenta mogu pročitati svi serveri • Svi oni primaju istu poruku • Klijent koji poziva CreateFile, može koristiti oblik \\*\mailslot\mailslotname da se spoji na sve mailslotove s danim imenom
Primjer korištenja mailslota Poruka se šalje periodički Mailslot Serveri Aplikacijski klijent 0 Mailslot Klijent Aplikacijski server hMS = CreateMailslot ("\\.\mailslot\status"); ReadFile (hMS, &ServerStatus) /* spoji se na server */ while (...) { Sleep (...); hMS = CreateFile ("\\*\mailslot\status"); · · · WriteFile (hMS, &StatusInformation) } · · · Aplikacijski klijent N hMS = CreateMailslot ("\\.\mailslot\status"); ReadFile (hMS, &ServerStatus) /* spoji se na server */
Korištenje mailslotova (1/2) • Scenarij: Aplikacijski server, kao primjerice server baze podataka, ponaša se kao mailslot klijent, periodički odašilje svoje ime, ime imenovane pipe, i statusne informacije • Bilo koji aplikacijski klijent, koji želi naći servera može primiti ove podatke postajući s time mailslot server • Primjetimo kako se koriste termini “klijent” i “server” • Aplikacijski server može periodički odašiljati svoj status (iskoristivost, veličinu baze podataka, itd.) aplikacijskim klijentima
Korištenje mailslotova (2/2) • Kao što je pokazano, postoji jedan mailslot klijent (pisač) i više čitača (mailslot servera) • S višestrukim aplikacijskim serverima, može se imati višestruke mailslot čitače i pisače • Servis “oglasne ploče” može imati jednog mailslot čitača i više pisača • Alternativa: Aplikacijski klijent se također ponaša kao mailslot klijent i odašilje ime pipe na mailslot i na aplikacijski server
Kreiranje i otvaranje mailslotova (1/3) HANDLE CreateMailslot (LPCTSTR lpszName, DWORD cbMaxMsg, DWORD dwReadTimeout, LPSECURITY_ATTRIBUTES lpsa) • lpszName — Pokazivač na ime mailslota oblika: \\.\mailslot\[path]name • cbMaxMsg • Maksimalna veličina (u byte-ima) za poruke koje klijent može pisati • 0 znači da nema ograničenja
Kreiranje i otvaranje mailslotova (2/3) • dwReadTimeout — Broj milisekundi koliko će operacija čitanja čekati • 0 znači trenutan povratak iz funkcije • MAILSLOT_WAIT_FOREVER je beskonačno čekanje (nema timeouta) • Klijent mora zadati FILE_SHARE_READ zastavicu • Funkcije GetMailslotInfo i SetMailslotInfo su slične odgovarajućim koje smo vidjeli kod imenovanih pipa
Kreiranje i otvaranje mailslotova (3/3) • Klijent (pisač), kada otvara mailslot s funkcijom CreateFile, koristi sljedeće oblike imena: • \\.\mailslot\[path]name • da dobije handle lokalnog mailslota (na istom stroju) • \\computername\mailslot\[path]name • da dobije handle mailslota na određenom stroju • \\domainname\mailslot\[path]name • da dobije handle koji predstavlja sve mailslotove na svim strojevima na domeni • \\*\mailslot\[path]name • da dobije handle koji predstavlja mailslotove na strojevima u sistemskoj primarnoj domeni