#include
#include
#include “cititorDinPipe.c”
int cdecl main (int argc, char **argv) {
HANDLE hPipeCitire;
// obtine un handle de citire din pipe
hPipeCitire = (HANDLE) atol (argv [1]);
// apeleaza rutina de citire din pipe
cititorDinPipe (hPipeCitire);
CloseHandle (hPipeCitire);
return (0);
}
Programul 3.27. Sursa PropozitiiPipeCititor.cpp
Pipe cu nume sub windows
Pipe cu nume este un mecanism de comunicare între două sisteme diferite, ambele fiind operaţionale pe platforme din clasa Microsoft: Windows 95, 98, 2000, NT, precum şi platforme mai vechi, ca OS/2, Novell, DOS (numai client). Este un IPC bidirecţional, cu facilităţi apropiate de cele ale comunicării prin socket [11].
În figura 3.10 sunt prezentate succesiunile apelurilor sistem, atât pentru server, cât şi pentru client. Cititorul poate uşor observa particularizările necesare pentru comunicarea prin pipe anonim.
-
CreateNamedPipe
-
ConnectNamedPipe
-
ReadFile 1. CreateFile
-
WriteFile 2. ReadFile
-
DisconnectNamedPipe 3. WriteFile
-
CloseHandle 4. CloseHandle
Server
Server
Pipe cu nume
Figura 3.10. Comunicarea prin pipe cu nume sub Windows
Crearea unui pipe cu nume se face prin apelul sistem:
CreateNamedPipe,
cu prototipul:
HANDLE CreateNamedPipe (
LPSTR numePipe,
DWORD optiuniModOpen,
DWORD optiuniModPipe,
DWORD nMaxInstances,
DWORD lungBufOut,
DWORD lungBufIn,
DWORD timeOut,
LPSECURITZ_ATTRIBUTES lpsa
)
unde:
numePipe
Este un string prin care se indică numele pipe-ului.
Convenţiile Microsoft de specificare a acestor nume impun două sintaxe, una pentru pipe local şi alta pentru pipe de pe o altă maşină. Aceste specificări sunt:
\\.\PIPE\numePipePeMAsina
\\adresaMasina\PIPE\numePipePeMasina
adresa maşinii este fie o specificare Internet, fie o adresă IP [1].
Atenţie! În constantele string de specificare a acestor nume, fiecare caracter \ trebuie dublat, aşa cum cer regulile de evitare specifice limbajului C.
optiuniModOpen
Specifică direcţia de deschidere a pipe-ului. Valoarea lui poate fi una dintre constantele:
PIPE_ACCESS_DUPLEX,
PIPE_ACCESS_INBOUND,
PIPE_ACCESS_OUTBOUND,
indicând fie ambele sensuri, fie numai de la client la server, fie numai de la server spre client.
optiuniModPipe
Precizează caracteristicile acestui pipe. Pentru specificare, se folosesc constante sau combinaţii legate între ele prin operatorul “|”.
-
PIPE_TYPEBYTE, PIPE_TYPE_MESSAGE pentru scrierea ca flux de octeţi,
respectiv ca şi mesaj;
-
PIPE_READMODE_BYTE, PIPE_READMODE_MESSAGE pentru citirea după regulile fluxului de octeţi sau citirea ca şi mesaj;
-
PIPE_WAIT, PIPE_NOWAIT pentru comunicarea sincronă, respectiv asincronă.
nMaxInstances
Specifică numărul de clienţi care se vor conecta la acest pipe. La nevoie, se poate folosi constanta
PIPE_UNLIMITED_INSTANCES.
lungBufOut şi lungBufIn
Specifică dimensiunile bufferelor, pentru ieşire şi intrare. Sistemul ia aceste numere doar ca sugestii, în funcţie de context el putând să redimensioneze aceste buffere.
timeOut
Indică, în milisecunde, durata maximă de aşteptare.
lpsa
Specifică atributele de securitate. De cele mai multe ori se specifică NULL, lăsând astfel pe seama sistemului fixarea acestora.
Apelul sistem întoarce un handle, care va fi folosit ca şi argument în celelalte apeluri sistem legate de pipe.
După crearea unui pipe cu nume, serverul apelează:
ConnectNamedPipe (HANDLE hNamedPipe; LPOVERLAPPED lpo=
Primul handle este cel întors de crearea pipe. Al doilea parametru, de regulă NULL,
indică faptul că se aşteaptă la conectare până când un client se conectează efectiv la pipe. (A se compara această regulă cu cea similară de la FIFO de sub Unix).
La fel ca şi la pipe anonime, se folosesc apelurile ReadFile şi WriteFile pentru schimbul cu pipe.
Serverul îşi încheie activitatea apelând:
DisconnectNamedPipe (HANDLE hNamedPipe);
CloseHandle )HANDLE hNamedPipe);
Pentru client, conectarea la un pipe cu nume presupune un apel sistem
CreateFile
Descriem aici, prototipurile funcţiilor de lucru cu fişiere sub Windows.
HANDLE CreateFile (
LPCTSTR numeFisier,
DWORD acces,
DWORD partajare,
LPSECURITY_ATTRIBUTES descr_sec,
DWORD mod_deschid,
DWORD atributeFisier,
HANDLE fis_atrib
);
unde:
numeFisier - Este numele fişierului care se va crea.
acces - Este modul de acces (în citire şi/sau scriere).
partajare - Este modul de partajare a fişierului.
mod_deschid - Este modul de creare a fişierului.
atributeFisier - Sunt atribute fi;ier.
În cazul creării unui pipe cu nume, numeFisier reprezintă numele pipe-ului, cu sintaxa specificată mai sus, la apelul CreateNamedPipe.
HFILE OpenFILE (
LPCSTR numeFisier,
LPOFSTRUCT lpBuf,
UINT uActiune
);
unde:
numeFisier – Este numele fişierului care se va deschide.
lpBuf - Este pointer la o structură care reţine informaţii despre fişier.
uActiune - Indică operaţia care se va efectua asupra fişierului.
BOOL WriteFile (
HANDLE hFisier,
LPCVOID lpBuf,
DWORD nNrOctetiDeScris,
LPDWORD lpNumarOctetiScrisi,
LPOVERLAPPED lStructIO
);
unde:
hFisier - Este handle-ul fisierului în care se va scxrie.
lpBuf - Este pointer la datele care se vor scrie în fişier.
nNrOctetiDeScris - Este numă de octeţi de scris.
1pNumarOctetiScrisi - Este pointer la numărul de octeţi scrişi efectiv.
lpStructIO - Este de obicei are valoarea NULL.
BOOL RedaFile (
HANDLE hFisier,
LPCVOID lpBuf,
DWORD nNrOctetiCititi,
LPOVERLAPPED lpStructIO
);
unde:
hFisier - Este handle-ul fişierului din care se va citi.
lpBuf - Este pointer la un bufer în care se vor citi datele.
nNrOctetiDeScris - Este număr de octeţi de citit.
lpNumarOctetiCititi - Este pointer la numărul de octeţi citiţi efectiv.
lpStructIO - Este de obicei are valoarea NULL.
BOOL CloseHandle (HANDLE hObject);
unde:
hObject - Este handle-ul la un obiect deschis.
Pentru mai multe informaţii legate de prototipurile acestor funcţii, se recomandă consultarea documentaţiei MSDN [83].
Drept exemplu de utilizare a acestui pipe, vom da încă o soluţie a problemei propoziţiilor. Considerăm că atât programul scriitor (în pipe), cât şi programul care citeşte din pipe se găsesc pe aceeaşi maşină.
Spre deosebire de pipe sub Unix, în cazul Windows creatorul resursei pipe trebuie să fie activ, pentru ca eventualii scriitori sau cititori să poată comunica folosind pipe-ul respectiv. De aceea, vom include operaţia de creare a pipe-ului în programul care scrie date în pipe.
Programul 3.28 indică sursa scriitorului în pipe (care este şi creatorul resursei pipe), iar Programul 3.29 indică sursa cititorului din pipe.
#include “scriitorInPipe.c”
#include
#include ”err_sys.cpp”
main ( ) {
Handle hNamedPipe;
// creeaza pipe/ul cu numele „propoz”
hNamedPipe =
CreateNamedPipe (\\\\.\\PIPE\\propoz,
PIPE_ACCESS_OUTBOUND | FILE_FLAG_WRITE_THROUGH,
PIPE_TYPE_BYTE | PIPE_WAIT, 3, dimBufIn, DimBufOut, TMOUT, NULL);
err_sys (hNamedPipe! = INVALID_HANDLE_VALUE);
// asteapta sa se conecteze un client
ConnectNamedPipe (hNamedPipe, NULL);
// apeleaza rutina de scriere in pipe
scriitorInPipe (hNamedPipe);
DisconnectNamedPipe (hNamedPipe);
CloseHandle (hNamedPipe);
}
Programul 3.28. Sursa PropozitiiFifiScriitor.cpp
#include
#include
#include ”cititorDinPipe.c”
#include ”err_sys.cpp”
main ( ) {
HANDLE hNamedPipe;
// deschide pipe/ul in citire
hNamedPipe =
CreateFile (*\\\\.\\PIPE\\propoz”,
GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
err_sys (hNamedPipe! = INVALID_HANDLE_VALUE);
// apeleaza rutina de citire din pipe
cititorDinPipe (hNamedPipe);
ClosedHandle (hNamedPipe);
}
Programul 3.29. Sursa PropozitiiFifoCititor.cpp
Invităm cititorul să construiască programele corespunzătoare surselor 3.22. (SemnaturaFifoScriitor.c) şi 3.23 (SemanaturaFifoCititor.c), în cazul mecanismului de comunicare pipe cu nume, sub Windows.
ANEXA 3 Comunicarea între procese Windows prin memorie partajată
Fişiere I/O mapate în memorie şi zone partajate
Maparea (găzduirea) fişierelor în memoria internă este o facilitate preluată de Windows NT de la sistemul de operare DOS. Această mapare permite aplicaţiilor să acceseze părţi ale fişierului mapat folosin pointeri din memoria internă, în loc de accesare a discului. Prin aceasta se obţine o viteză de acces mult mai mare. Printre alte avantaje ale mapării, mai amintim faptul că se beneficiază de mecanismul de cache-ing şi de paginare a memoriei interne, oferit de Windows NT.
O aplicaţie poate mapa fişiere de la 1 octet până la 2G octeţi. Fişierele mapate în memorie permit, de asemnea, ca două sau mai multe procesoare să partajeze aceste fişiere şi implicit să partajeze memoria internă.
În continuare, prezentăm o succesiune de 5 (cinci) paşi ce trebuie urmaţi de orice aplicaţie Windows care foloseşte o zonă de memorie partajată:
-
Crearea segmentului de memorie partajată folosind funcţia CreateFileMapping.
Această operaţie se poate realiza î două moduri:
-
folosind un fişier definit anterior de către utilizator, cu ajutorul apelurilor CreateFile sau OpenFile.
-
Folosind o pagină sistem, specificată cu ajutorul unui handler predefinit, cu valoarea 0xFFFFFFFF.
Dacă segmentul de memorie partajată există deja, deschiderea accesului la segment se obţine cu ajutorul funcţiei OpenFileMapping. Obiectul Windows, asociat segmentului de memorie partajată, poartă numele de file-mapping. Atât funcţia CreateFileMapping, cât şi funcţia OpenFileMapping întorc un handle la obiectul file-mapping asociat segmentului de memorie partajată referit.
-
Maparea propriu-yisă a segmentului de memorie partajată (reprezentat prin
obiectul file-mapping), în spaţiul de memorie al procesului curent, este realizată cu ajutorul apelului MapViewOfFile. Această funcţie întoarce un pointer la o porţiune din această memorie partajată.
-
Pointerul obţinut în urma apelului precedent, permite aplicaţiei apelante să
acceseze zona de memorie partajată în citire şi/sau scriere, în funcţie de parametrii specificaţi la apel.
-
Operaţia complementară celei de mapare, se realizează cu ajutorul apelului UnmapViewOfFile. Astfel, se realizează ”detaşarea” aplicaţiei curente de la segmentul de memorie partajată, prin eliberarea spaţiului de memorie ocupat prin operaţia de mapare.
-
În final, închiderea handle-ului la obiectul file-mapping se realizează cu funcţia CloseHandle. De asemenea, folosind CloseHandle, se închide fişierul deschis cu CreateFile sau OpenFile.
Crearea/deschiderea în varianta 1.b, cu handle-ul special 0xFFFFFFFF permite folosirea unei singure zone partajate în sistem. Folosind numai acest handle, NU este posibil ca pe acelaşi sistem să existe mai multe zone de memorie partajată. Pentru a permite ca fiecare grup de procese să-şi folosească propria zonă de memorie partajată, trebuie să se folosească crearea/deschiderea în varianta 1.a, CreateFile/OpenFile. Astfel, se creează/deschide câte un fişier mapat în memorie pentru fiecare zonă de memorie partajată dorită.
În continuare, punctăm o comparaţie, la nivel API, între operaţiile de lucru cu memorie partajată sub Unix şi sub Windows:
CreateFileMapping - -> shmget
MapViewOfFile - -> shmat
UnmapViewOfFile - -> shmdt
CloseHandle - -> shmctl
Sintaxa exactă a funcţiilor implicate în utilizarea segementelor de memorie partajată sub Windows, va fi descrisă mai jos.
Prototipurile funcţiilor CreateFile, ReadFile şi WriteFile au fost prezentate în 3.2.3.2.
Prototipurile celorlalte funcţii folosite sunt descrise în continuare:
HANDLE CreateFileMapping (
HANDLE hFis,
LPSECURITY_ATTRIBUTES descr_sec,
DWORD prot,
DWORD maxHigh,
DWORD maxLow,
LPCTSTR nume_file_mapping
) ;
unde:
hFis - Este handle la fişierul de mapat; valoarea 0xFFFFFFFF pentru acest
parametru indică o pagină implicit sistem.
descr_sec - Este descriptor de securitate; dacă se specifică valoarea NULL pentru
acest parametru, sistemul va folosi atributele de securitate implicite.
prot - Este atributul de protecţie pentru obiectul de mapat.
maxHigh şi maxLow - Compun dimensiunea pe 32 de biţi a obiectului de mapat. nume_file_mapping - Este numele obiectului file mapping
HANDLE OpenFileMapping (
DWORD acces,
BOOL bHandleMostenire,
LPCTSTR nume_file_mapping
) ;
unde:
acces - Indică modul de acces (citire şi/sau scriere).
bHandleMostenire - Indică dacă obiectul file-mapping va fi moştenit de
eventuale procese fii.
nume_file_mapping - Este numele obiectului file-mapping.
LPVOID MapViewOfFile (
HANDLE hFileMap,
DWORD acces,
DWORD offsetHigh,
DWORD offsetLow,
DWORD nrOctetiDeMapat
) ;
unde:
hFileMap – Este handle la obiectul file-mapping (handle returnat de
CreateFileMapping).
acces – Indică modul de acces (citire şi/sau scriere).
offsetHigh şi offsetLow - Compun offsetul pe 32 de biţi, a zonei de memorie de
mapat.
nrOctetiDeMapat – Este numărul de octeţi de mapat.
BOOL UnmapViewOfFile (LPCVOID lpAdresaMapata);
unde:
lpAdresaMapata – Este adresa de memorie unde începe maparea
Pentru mai multe informaţii legate de semnificaţia parametrilor şi prototipurilor funcţiilor ce operează cu memorie partajată sub Windows, se recomandă consultarea documentaţiei MSDN.
Implementarea foii de calcul sub Windows
Aplicaţia de mai jos implementează calculul tabelar pentru problema definită în 3.3.1. Programul 3.35 este fişierul header al aplicaţiei, similar Programului 3.31.
#include
#include
#include
#include
#include
#include
#include “semnaturaTemporala.cpp”
#define SMAX 1000
struct foaie_de_calcul {
char s[4] [100];
int v[4];
};
#define LUNFIME siyeof (struct foaie_de_calcul)
#define NUME_SEGMENT_MEMORIE_PARTAJATA “MemoriaMeaPartajata”
Fişierul header defineşte foaia de calcul, lungimea acesteia şi defineşte numele segmentului de memorie partajată.
La fel ca în cazul comunicării folosind pipe, şi mecanismul de comunicare folosind memorie partajată, sub Windows, presupune că creatorul obiectului file-mapping este activ, cât timp scriitorii şi cititorii partajează resursa respectivă. De aceea, vom include operaţia de creare a obiectului file-mapping în programul care accesează obiectul file-mapping în scriere.
Sursele programele scriitor şi cititor sunt prezentate în Programul 3.36, respectiv 3.37.
#include “memPartFoaieWin.h”
// 0
#define NR_ITER 100
int main ( ) {
int it, shmd, i, x,;
struct foaie_de_calcul *mp;
char s [SMAX];
HANDLE handleMemoriePartajata;
// creeaza obiectul file-mapping
handleMemoriePartajata =
CreateFileMapping (
(HANDLE) 0XFFFFFFFF, NULL,
PAGE_READWRITE, 0,
sizeof (struct foaie_de_calcul),
NUME_SEGMENT_MEMORIE_PARTAJATA);
assert (handleMemoriePartajata! = NULL);
mp = (struct foaie_de_clacul *)MapViewOfFile (
handleMemoriePartajata, FILE_MAP_WRITE, 0, 0, 100);
assert (mp! = NULL);
// 1
for (it = 0; it
i = rand ( ) % 3 ;
x = 1 + rand ( ) % 99;
strcpy (s, semanaturaTemporala ( ) );
// 2
strcpy (mp - >s [i], s);
mp -> v [3] = mp -> v [3] - mp ->v [i] + x;
mp -> v [i] = x;
strcpy (mp -> s[3], s);
//3
}
UnmapViewOfFile (mp);
CloseHandle (handleMemoriePartajat);
//4
}
Programul 3.36. Sursa memPartScriitorFoaie.cpp
#include “memPartFoaieWin.h”
#define NR_ITER 50
int main ( ) {
int it, shmd, i, x, j;
struct foaie_de_calcul *mp, *copie;
char s [SMAX];
HANDLE handleMemoriePartajata;
// deschide un obiect file-mapping
handleMemoriePartajata = OpenFileMapping (
FILE_MAP_READ, 0, NUME_SEGMENT_MEMORIE_PARTAJATA);
assert (handlerMemoriePartajata! = NULL);
mp = (struct foaie_de_calcul *)
MapViewOfFile (handleMemoriePartajata,
FILE_MAP_READ, 0, 0, 0);
assert (mp! = NULL);
copie = (struct foaie_de_calcul * ) malloc (sizeof (struct foaie_de_calcul ) );
for (it = 0; itfor (j=0;j<4; j++) {
copie -> v[j] = mp -> v [j];
strcpy (copie) -> s [j], mp -> s[j] );
}
strcpy (s, semanaturaTemporala ( ) );
x = copie -> v [3] – copie -> v [0] – copie -> v[1] – copie -> v[2];
i = o;
if (strcmp (copie -> s[3], copie -> s[0] ) && strcmp (copie -> s [3],
copie -> s[1]) && strcmp (copie -> s[3], copie -> s [2]) )
i = 1;
printf (“citire: %s”, s);
if (i) printf (“\tSemnatura total eronata!”);
if (x) printf (“\%d este diferenta la total!”, x);
printf (“\n”);
for (i=o; i<4; i++)
printf (“%s\t%d\n”, copie -> s [i], copie -> v [i] );
printf (“\n”);
}
UnmapViewOfFile (mp);
CloseHandle (handleMemoriePartajata);
}
Programul 3.37. Sursa memPartCititorFoaie.cpp
Dostları ilə paylaş: