Anda di halaman 1dari 12

Implementarea standardului IEEE 802.

3 in retele NOVELL

Avind in vedere independenta fata de placile de retea datorate standardizarii Novell a creat doar o implementare
a nivelului MAC care in acelasi timp poate asigura unele servicii din nivelul de retea pentru a permite o extindere prin
bridges a retelelor mici.Structura software intr-o retea Novell este urmatoarea:

Adaptarea driver-ului de retea la configuratia placii(intreruperi,adrese)se face utilizind linia de comanda iar
adaptarea la IPX se face cu utilitarul WSGEN.Acesta va crea un IPX.COM care va putea comunica cu driver-ul de retea
utilizind intreruperile de acces ale acestuia.
Driver-ul de retea va face transmisia la nivel fizic a pachetelor, care sint transmise acestuia de IPX ,prin
intermediul placii de retea.Putem avea mai multe placi de retea cu diverse protocoale sau doar in diverse retele cu
acelasi protocol legate la acelasi sistem de operare ceea ce creaza o mai mare flexibilitate a topologiei retelei.
IPX(Internetwork Packet eXchange) este un protocol realizat de firma Novell care realizeaza transmisia
pachetelor primite de la NetWare Shell .IPX instaleaza in spatiul de intreruperi libere ale DOS propriile intreruperi prin
care shell-ul va realiza apelul de functii.Folosind aceste intreruperi se pot realiza aplicatii de sine statatoare care sa
realizeze transferuri de informatii in retea. Apelul se poate face si altfel nu doar prin intreruperi daca exista biblioteci de
compilare in limbaje de nivel inalt.Transmisia se face utilizind pachetele date de standardul IEEE 802.3 :

Cimpurile din frame-ul prezentat sint urmatoarele:


1.Preambul format din 7 octeti 10101010 va produce 10 Mhz si destinata-rul se va putea sincroniza.
2.Un octet care va anunta sfirsitul perioadei de sincronizare si inceputul pachetului este 10101011.
3.Adresa destinatarului de 6 octeti .
4.Adresa expeditorului de 6 octeti.
5.Lungimea cimpului de date pe doi octeti.
6.Cimpul de date are intre 0 si 1500 de octeti.
7.PAD cimp de completare a astfel incit sa aiba minim 64 de octeti .Va completa cimpul de date cu un nr. de
octeti intre 0 si 46 citi lipsesc pentru ca pachetul sa aiba 64 de octeti fara preambul si octetul aferent.
8.4octeti pentru controlul CRC la destinatie .
Header-ul pus de IPX contine adresa destinatarului si a expeditorului header realizat insa de shell in momentul
cind transmite comanda de realizare a comunicatiei.IPX implementeaza si unele functii ale nivelului de retea putind
realiza routarea pachetelor si transmisie intre retele.La receptie IPX primeste de la driver pachetul care nu contine octetii
de sincronizare doar adresele sursei si ale destinatarului IPX testeaza daca pachetul are adresa corespunzatoare
procesului care asteapta daca nu corespunde pachetul nu va fi luat in considerare ca si cind nu ar fi sosit.
Adresarea foloseste trei cimpuri de adresare o adresa de retea formata din 6 octeti ,o adresa de nod formata din
2 octeti care indica calculatorul si o adresa de socket care indica aplicatia .Aceasta adresa de socket permite mai multor
aplicatii de a comunica in acelasi timp pe aceeasi placa de retea total independent una de cealalta.Aceasta facilitate
este foarte importanta la acest nivel deoarece IPX este un protocol cu comutare de pachete si nu garanteaza livrarea
pachetelor sau ordinea lor,aceasta face ca in momentul unei receptii in care avem de primit mai multe pachete care vor
urma cai diferite sa fie necesara deschiderea de mai multe socketuri chiar de aceeasi aplicatii pentru a da crea IPX-ului
posibilitatea de a salva pachetele sosite chiar daca ele sosesc aproape in acelasi timp nedind posibilitatea nivelului
superior sa goleasca buffer-ul (IPX-ul in momentul in care primeste un pachet si are buffer-ele ocupate va renunta la
pachet).
Pentru a imbunatati acest protocol s-a realizat o adaptare a procolului companiei Xerox SPX(Sequenced Packet
eXchange) care implementeza o serie de servicii ale nivelului de transport.SPX este un protocol orientat conexiune care
garanteaza livrarea pachetelor si ordinea lor.Pentru aceasta SPX utilizeaza serviciile de comunicare ale IPX ,deschide o
conexiune dupa care incepe sa transmita pachete asteptind in acelasi timp de la destinatar nu numai mesajul ca
pachetul a sosit dar o valoare a unui algoritm de verificare astfel incit sa aiba certitudinea ca pachetul a ajuns nealterat.
NetWare shell este un program rezident care intercepteza intreruperi ale DOS redirectind apoi catre fileserver
unele cereri ale aplicatiilor.Fileserverul utilizeaza un sistem de operare dedicat NetWare Operating System si foloseste
pentru dialogul cu NetWare shell un protocol al firmei numit NetWare Core Protocol.Exista shell-uri pentru toate
variantele DOS mai mari de 3.3 si pentru variante noi exista shell-uri care lucreaza in memoria extinsa sau ex-
pandata.Aceste shell-uri indirecteaza intreruperile 24h (intreruperea de eroare critica ) 17h(pentru imprimanta) si 21h la
care verifica toate functiile.Dupa verificarea functiilor shell-ul va transforma apelul DOS intr-o cerere NCP si o va
transmite IPX-ului pentru a fi livrata file-server-ului,unde sistemul de operare NetWare o va rezolva si va trimite
rezultatele inapoi tot pe baza NCP prin intermediul IPX.Astfel tratarea serviciilor de retea este transparenta aplicatiei si in
consecinta utilizatorului.
IPX pune la dispozitie shell-ului o serie de functii suficient de mare astfel incit shell-ul sa poata realiza toate
serviciile de retea printr-un singur apel IPX.Aceste functii se impart in clase de servicii ,clasa care ne intereseaza este
clasa de comunicatii.

2. Descrierea functiilor de comunicatii IPX si a noilor functii

Inainte de a face un apel IPX este necesara pregatirea unui header in care va trebui specificata adresa
,mesajul ,lungimea si alte caracteristici dintre care o parte constituie chiar header-ul MAC iar restul sint folosite de IPX
pentru tratarea cererii shell-ului sau a altei aplicatii care face cereri catre IPX.
Datele necesare IPX sint formate din doua structuri mari:
-header-ul IPX care contine:- adresa expeditorului
- adresa destinatiei
- lungimea cimpului de date
- tipul pachetului
- suma de contol
- un octet pentru controlul transportului
Adresele sint formate asa cum am mai spus din 4 octeti adresa de retea 6 octeti adresa de nod si 2 octeti adresa
de socket.Pentru a putea crea acest header sint necesare citeva apeluri IPX preliminare pe care le voi descrie mai jos.
-ECB(Event Control Block)prin care IPX comunica apelantului erorile sau legaturile corect efectuate.Acest bloc
contine urmatoarele cimpuri:
-adresa rutinei unde va fi dat controlul in cazul unui eve-niment,care poate fi receptie transmisie
cu succes sau nu.Aceasta rutina poate fi folosita cind se doreste intreruperea programului in momentul in care apare un
eveniment in transmisie.Nu este indicata folosirea acestei rutine deoarece in timpul tratarii ei toate intreruperile
mascabile sint dezactivate si daca este prea lunga sistemul se poate agata.
-un octet denumit 'in use flag' si care este nenul atit timp cit IPX trateaza legatura(prin legatura
intelegind o transmisie sau o receptie)Acest octet este folosit pentru a face pooling cind nu se folosesc intreruperi la
revenirea din IPX (cind ESR address este 0).
- alt octet de control este 'completionCode' care indica re-alizarea cu succes a serviciului(0)
cerut sau nu(1).Este folosit la verificarea terminarii cu succes a apelului IPX aceasta nu inseamna ca pachetul a ajuns
sau daca a ajuns ca e corect ,doar ca IPX l-a transmis.
-socketNumber este un 'cuvint' care indica adresa de socket a procesului .Prin aceasta adresa
se pot diferentia aplicatii sau se poate mari nr. de buffer-e in care va receptiona,necesara cind se asteapta receptia unui
nr. mare de pachete intr-un timp scurt si altfel programul nu ar avea timp sa elibereze buffer-ele si IPX ar renunta la
pachetele care sosesc cind toate buffer-ele sint ocupate.IPX nu va pune in ordine pachetele deci va fi necesara o
cautare a pachetelor in buffer-e,nu le pune in ordinea sosirii in ordinea crescatoare a socket-ului deoarece se poate ca si
pachetele sa soseasca in alta ordine deci ar fi inutila alegerea socket-ului.Adresarea NETWARE foloseste o adresa de
retea, una de nod si un socket.Adesa de retea este folosita pentru a identifica reteaua atunci cind avem mai multe retele
interconectate ,adresa de nod este data de placa fizic de pe care se face transmisia sau la care se face receptia iar
adresa de socket va da procesul care va primi pachetul deoarece mai multe procese pot comunica folosind aceeasi
placa de retea.Pentru a putea folosi aceste adresari trebuie ca inainte de lansarea oricarui program ce le foloseste sa
avem lansate IPX.COM sau IPX.COM si SPX.COM in functie de ce serviciu vom folosi.Lansarea acestor programe va
duce la generarea unei adrese de nod pentru respectiva placa,adresa de retea este data de server si se stabileste la
instalare.
-un alt cimp important este 'immediateAddress' format din 6 octeti si care intoarce la sosirea
unui pachet adresa expeditorului.La transmisie va fi incarcata adresa expeditorului.Folosind acest cimp se poate
transmite imediat un raspuns ,fara a cunoaste anterior adresa acestuia.Astfel se pot realiza sesiuni de comunicatie intre
mai multe statii ,pentru intrarea unei statii noi in circuit aceasta va transmite broadcast un mesaj (am presupus ca
arbitrarea intrarii in sesiune ramine distribuita) astfel ca toate statiile stiu noua statie iar in functie de organizarea logica a
sesiunii o stie ii va comunica
Functiile de comunicatie folosite de IPX sint urmatoarele:
IPXCancelEvent(ECB *);
IPXCloseSocket(WORD);

2
IPXDisconnectFromTarget(BYTE *);
IPXGetDataAddress(BYTE *, WORD *);
IPXGetInternetworkAddress(BYTE *);
IPXGetIntervalMarker(void);
IPXGetLocalTarget(BYTE *, BYTE *, int *);
IPXGetProcAddress(WORD *, WORD *);
IPXInitialize(void);
IPXListenForPacket(ECB *);
IPXOpenSocket(BYTE *, BYTE);
IPXPacket(ECB *, WORD);
IPXRelinquishControl(void);
IPXScheduleIPXEvent(WORD, ECB *);
IPXScheduleSpecialEvent(WORD, ECB *);
IPXSendPacket(ECB *);

Orice comunicatie IPX se incepe prin initializare cu IPXInitialize() ceea ce va duce la asignarea unei adrese de
retea nodului ce va putea fi folosita in comunicatia cu alte statii. Aceasta adresa se poate afla folosind functia
IPXGetInternetworkAddress care va intoarce in argument adresa de retea si nod in aceasta ordine.
Similar inainte de a transmite trebuie sa deschidem un socket de pe care sa realizam transmisia cu
IPXOpenSocket si in caz de reusita se poate face transmisia.Argumentele sint o adresa de socket (care este un intreg)
si tipul socket-ului.
IPXSendPacket si IPXListenForPacket sint folosite la receptia respectiv transmisia unui pachet care este dat
de ECB prin dimensiune si un pointer la inceputul sau.
Exista doua functii speciale :IPXRelinquishControl care cedeaza controlul sistemului in timp ce se face o
comunicatie ,semnalizarea terminarii operatiei se face tratind rutina ESR daca s-a prevazut una sau se face o testare
periodica a variabilei ' inUseFlag ' a structurii ECB corespunzatoare.O alta functie speciala este IPXCancelEvent care
este folositan pentru a intrerupe efectuarea serviciului cerut.Aceste doua functii se folosesc in principal pentru a realiza
iesirea dintr-o bucla de asteptare a unui pachet ,ce poate deveni infinita daca pachetul nu soseste si va bloca
calculatorul.
Principiul de realizarea a unei transmisii este ilustrat in continuare :

Initializare IPX
Afisare a adresei nodului si a retelei
|
Creare IPXHeader
|
Initializare IPXHeader
|
Creare ECB
|
Initializare ECB
|
Deschidere socket
|
IPX Send/ReceivePacket
|
ecb->inUseFlag!=0 -------NU
DA |
IPXRelinquishControl |
|------------------------|
ecb->completionCode=0-----NU----------------EROARE
DA
|
Transmisia/Receptia e OK

Observam ca de fiecare data cind se doreste executia unei comunicatii este necesara alocarea de memorie
pentru header-ul IPX pentru ECB si pentru socket.Suplimentar daca dupa IPXRelinquishControl avem o testare a break-
ului atunci trebuie avut grija ca parasirea IPX sa se faca cu IPXCancelEvent altfel dupa un timp calculatorul se va bloca
avind in vedere ca IPX va continua sa execute o cerere de comunicare desi nu mai are header ,ecb,sau socket deschis
blocare care se poate produce oricind ducind la aparitia unor erori aparent aleatoare foarte greu de depistat.
Exista doua tipuri de dificultati :pentru programatorii care nu cunosc teoria schimbului de date pe IPX si care vor
doar sa scimbe la un moment dat citeva pachete vor trebui sa studieze destul de mult pentru a face un singur transfer,iar
programatorii cunoscatori vor putea foarte usor gresi datorita repetarii aceluiasi tip de prelucrari .
Evitarea acestor posibile viitoare erori se poate face realizind citeva functii pentru a putea realiza un transfer de
mesaj cu o singura functie fara a mai fi interesat de apelurile care vor deveni apeluri ' joase ' deschidere socket sau

3
realizare header.Noile functii trebuie sa inglobeze toate apelurile anterioare si sa intoarca erori diferite in functie de
problemele aparute astfel incit utilizatorul sa poata testa usor care a fost problema .
Astfel vom trece de la un nivel de programare in care trebuia gestionat sistemul la un nivel de programare in
care vom gestiona aplicatia. si nevoile ei iar erorile de transmisie vor fi intoarse de functiile de transmisie exact la fel
cum o fac si functiile grafice de ex.
Am creat doua functii de initializare a header-ului IPX si a ECB-ului penntru a inlatura monotonia adusa de
acestea si in acelasi timp pentru a putea micsopra greselile aduse de apelurile repetate unde este necesara o initializare
repetata . Parametrii de initializare sint parametri de apel ai functiilor pentru a asigura un inalt grad de flexibilitate a lor.

/*
Functia initializeaza un ECB pentru ascultare de pachete.
*/

void IInitLisPacket(IPXHeader *h, ECB *ecb, char *buf, int dim, unsigned IPXSocket)
{

ecb->ESRAddress = 0; /* nu se initializeaza o rutina de tratare a


intreruperilor deoarece o astfel de rutina ar trebui sa fie dedicata procesului pentru
a putea realiza o tratarea diferita a evenimentelor in functie de cerintele procesului
si s-a dorit o functie care sa fie foarte generala si foarte flexibila.In acelasi timp am
presupus ca aceasta functie va fi inglobata in altela astfel incit sa usureze munca celor
care nu cunosc foarte bine comunicatiile IPX iar foloisrea unei rutine de tratare a
evenimentelor presupune un inalt grad de cunoastere a lucrului IPX si in asamblor pentru
80x86.*/
ecb->inUseFlag = 0;
ecb->socketNumber = IPXSocket;
ecb->fragmentCount=2;
ecb->fragmentDescriptor[0].address=h;
ecb->fragmentDescriptor[0].size=sizeof(*h);

ecb->fragmentDescriptor[1].address=buf;
ecb->fragmentDescriptor[1].size = dim;
}

Ultimele patru cimpuri sint folosite pentru a micsora nr. de argumente al unui apel IPX ,deoarece apelul se face
astfel doar dindu-se adresa ECB ,structura care contine toate cele necesare receptiei( IPXListPacket( ecb ) ).Cimpul [0]
contine adresa header-ului ce va fi folosit pentru comunicatie iar cimpul [1] contine buffer-ul unde va fi depus mesajul.

/*
Functia initializeaza un ECB si un IPXHeader pentru trimitere pachete .
*/

void IInitSendPacket(IPXHeader *h, ECB *ecb,char *buf, int dim,unsigned


IPXSocket,unsigned char *targetNode,unsigned char *targetNetwork)
{
int i;

/* Initialize the send message ECB */


ecb->ESRAddress=0; /* nu se initializeaza o rutina de tratare a intreruperilor
deoarece o astfel de rutina ar trebui sa fie dedicata procesului pentru a putea realiza
o tratarea diferita a evenimentelor in functie de cerintele procesului si s-a dorit o
functie care sa fie foarte generala si foarte flexibila.In acelasi timp am presupus ca
aceasta functie va fi inglobata in altele astfel incit sa usureze munca celor care nu
cunosc foarte bine comunicatiile IPX iar folosrea unei rutine de tratare a evenimentelor
presupune un inalt grad de cunoastere a lucrului IPX si in asamblor pentru 80x86.*/

ecb->inUseFlag = 0;
ecb->socketNumber = IPXSocket;
ecb->fragmentCount=2;
ecb->fragmentDescriptor[0].address=h;
ecb->fragmentDescriptor[0].size = sizeof( *h );
ecb->fragmentDescriptor[1].address=buf;
ecb->fragmentDescriptor[1].size = dim;
Ultimele patru cimpuri sint folosite pentru a micsora nr de argumente al unui apel
IPX ,deoarece apelul se face astfel doar dindu-se adresa ECB ,structura care contine

4
toate cele necesare transmisiei ( IPXSendPacket( ecb ) ).Cimpul [0] contine adresa
header-ului IPX ce va fi folosit pentru comunicatie iar cimpul [1] contine buffer-ul de
unde va fi preluat mesajul .

movmem(targetNode,ecb->immediateAddress,6);
h->packetType = 4;
movmem(targetNetwork,h->destination.network,4);
movmem(targetNode,h->destination.node,6);
movmem(&IPXSocket,h->destination.socket,2);
}

Astfel se face directarea pachetului catre adresa de retea data de cele 3 componente care le-am detaliat mai sus:adresa
de retea ,de nod ,de socket ultima fiind necesara daca se face transmisia foarte restrictiv (procesul de destinatie
foloseste mai multe socket pentru diverse aplicatii ,protocoale etc.) altfel destinatia nu va lua in considerare depunind
mesajul intr-un socket liber urmind ca destinatarul sa caute ordinea pachetelor.
Cu aceste doua functii am realizat doar primul pas in incapsularea dorita a apelurilor de functii de
comunicatie .Urmatorul pas va duce la rezultatul mult dorit pentru aceasta e necesar sa stim care sint principalele functii
necesare intr-o aplicatie distribuita.Acestea sint destul de putine ,experientele facute in realizarea unui sistem distribuit
arata ca in principal sint necesare trei functii si anume :
-una de transmisie a unui mesaj oarecare la o adresa oarecare. Aceasta va fi folosita pentru a realiza
toate transmisiile necesare pentru aplicatie, oricit de diverse transmisia realizindu-se de pe un singur socket oricit de
complicata ar fi si deci este suficient un tip de functie care va putea realiza orice transmisie .Bineinteles lucram in
ipoteza ca transmisia se face intr-o retea locala unde in general transmisia este fara probleme.
- functiile de receptie sint de doua feluri in realizarea unui sistem distribuit :
1. de receptie a unui anumit pachet (cu un anumit continut care se cunoaste dinainte) si intereseaza
doar adresa celui care la trimis .Aceasta functie e folosita la initializarea sistemului cind statiile priemsc cereri de
inregistrare in liste si transmit aprobari (in functie de logica de realizare adoptata) si apoi la sincroniozari cind asteapta
doar aprobari ( acum nu interseaza nici macar cine a transmis ,iar in functie de sistemul de sincronizari adoptat ,ci doar
daca soseste mesajul util de unde trebuie).
2. de receptie in general .Aici ne intereseaza continutul pachetului si trebuie avut grija la modul in care
se face receptia .Functia realizeaza receptia pe un singur socket si in functie de bucla in care se realizeaza receptia va fi
necesara o intirziere a salvelor de pachete pentru o receptie foarte buna ,intirziere care se face la expeditor.

Functia de trimitere a pachetelor la adrese oarecare


Parametrii functiei vor fi constituiti din adresa nodului spre care se face transmisia ,un pointer catre mesaj si
dimensiunea mesajului .Toti parametrii functiei sint deci variabile oarecare ale programului cu exceptia adresei care
trebuie cunoscuta dar nu e necesar sa fie cunoscuta in momentul realizarii aplicatiei ea se poate afla in momentul
receptionarii unui mesaj,care poate fi initial trimis catre toate statiile din retea (apelul broadcast se realizeaza folosind ca
adresa de nod adresa FFFFFF ,adresa de retea 0000 este adresa locala de fapt nu conteaza decit atunci cind in retea
exista un router care poate fi deranjat de anumite adrese sau care va deranja alte retele).

5
Are urmatoarea organigrama :

Aloc spatiu pentru IPXHeader si ECB


|
Alocare corecta?--------NU-------intoarce 1
|
Deschide socket
|
Deschis corect?---------NU---elibereaza memoria
| |
| intoarce 2
|
Tasta apasata in timp ce trimite mesaj?------DA
| |
NU---------- Mesaj transmis corect ? IPXCancelEvent()
| | |
elibereaza memoria elibereza memoria elibereaza memoria
| | |
inchide socket inchide socket inchide socket
| | |
intoarce 4 | intoarce 3
|
Intoarce 0

Aceasta este functia :

int SendPacket(BYTE *targetNode,char *mesaj,WORD dim){

ECB *ecb;

IPXHeader *packetHeader;

WORD sourceSocket;

WORD targetSocket = 0x0050;


BYTE targetNetwork[4] = { 0, 0, 0, 0 };

/*Se initializeaza IPXheader-ul si ECB-ul pentru transmiterea pachetului de date */

if((packetHeader=farmalloc(sizeof(IPXHeader)))!=NULL){
if((ecb=farmalloc(sizeof(ECB)))!=NULL)

IInitSendPacket(packetHeader,ecb,mesaj,dim,targetSocket,targetNode,targetNetwork);
}
else
return(1); /* eroarea de alocare de memorie pentru header si ecb este 1*/

/* Se deschide socket-ul pentru trimiterea pachetului */

if(!IPXOpenSocket( (void *)&sourceSocket, TEMPORARY_SOCKET))


{
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
farfree(packetHeader);
farfree(ecb);
return(2); /* eroarea de deschidere a socket-ului este 2*/
}
/* Are loc transmiterea efectiva a pachetului*/

IPXSendPacket( ecb );
while ( ecb->inUseFlag ){
IPXRelinquishControl();
if( bioskey(1) ){

6
getch();
IPXCancelEvent(ecb();
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
farfree(packetHeader);
farfree(ecb);
return(3); /*eroarea 3 este break ,evita blocarea la transmisie */
}
}

if ( !ecb->completionCode ){
IPXCloseSocket( sourceSocket );

/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/


farfree(packetHeader);
farfree(ecb);
return(0); /* pachetul a putut fi transmis in bune conditii */
}
else{
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
farfree(packetHeader);
farfree(ecb);
return(4); /*eroarea nr. 4 : pachetul nu a putut fi transmis in bune conditii */

}
}
Toti parametrii specifici IPX adica header-ul ,ecb,socket sint proprii functiei utilizatorul nu mai are acces la ei si
nici nu il vor mai deranja .Apelul catre IPX devine astfel transparent pentru utilizator.In acelasi timp s-a realizat o
clasificare a erorilor care pot sa apara (bineinteles ca aceasta se face cu pierderea semnalului de eroare, care apare in
momentul deschiderii socket-ului, a unei transmisii defectuoase dar cum am considerat ca utiliaztorul oricum nu
cunoaste amanunte nu ii sint necesare aceste detalii)in patru clase :
-insuficienta memorie pentru alocarea de spatiu necesar IPXHeader si ecb
-esuarea deschiderii socket-ului
-intreruperea rularii de catre utilizator
-transmisia a esuat din cauza nivelelor inferioare
In cazul unei transmisii cu succes functia intoarce 0.Utilizatorului ii ramine sa faca un ' switch ' si va fi anuntat daca are
probleme la transmisie.Aceste intreurperi vor fi pastrate pentru toate functiile ,consecventa fiind necesara tot pentru o
programare mult mai usoara si mai prietenoasa.
Intr-o retea locala aceasta functie asigura o transmisie sigura a pachetelor si in acelasi timp sosirea in ordine la
destinatie .Acest lucru este asigurat prin faptul ca nu exista decit o singura cale intre sursa si destinatie ceea ce obliga
IPX-ul sa pastreze ordinea pachetelor pe singura cale disponibila.

Organigrama functiei de receptie a unui anumit pachet este urmatoarea:

7
Aloc spatiu pentru IPXHeader si ECB
|
Alocare corecta?--------NU-------intoarce 1
|
Deschide socket
|
Deschis corect?---------NU---elibereaza memoria
| |
| intoarce 2
|
Tasta apasata in timp ce primeste mesaj?------------DA
| |
NU----------------Mesaj primit corect? IPXCancelEvent()
| | |
elibereaza memoria Mesajul primit e corect?--NU elibereaza memoria
| | | |
inchide socket DA | inchide socket
| | | |
intoarce 4 inchide socket | intoarce 3
| |
| elibereaza memoria
Intoarce 0 |
+ inchide socket
adresa expeditor |
intoarce 5

Am pastrat aceleasi erori ca si in functia anterioara si am mai introdus o noua eroare care poate apare si anume
primirea unui pachet diferit de cel asteptat ceea ce poate duce la oprirea procesului printr-un break automat sau cererea
unei resincronizari de ex. in functie de locul unde apare axest mesaj.Am spus resincronizari pentru ca astfel de mesaje
speciale (cu un anumit continut ) sint asteptate de obicei in momentele de sincronizare sau la realizarea initiala a
sistemului.Aceasta functie poate fi folosita in oricare dintre situatii deoarece pe linga testarea mesajului si raportarea
rezultatului intoarce si adresa expeditorului astfel ca se poate sti de unde a sosit mesajul si decide daca este un mesaj
intirziat sau unul de eroare.In acelasi timp se face si economie de memorie deoarece nu se intoarce tot mesajul ci doar
rezultatul comparatiei, la mesajul primit se renunta odata cu eliberarea memoriei alocate pentru receptie.
Functia de receptionare a unui mesaj este urmatoarea:

int receiveMessage(unsigned char *packetAddress,char *mesaj,char dim){

ECB *ecb; /* receive ecb */

IPXHeader *packetHeader; /* receive packet */

WORD sourceSocket=0x0050,targetSocket=0x0050;
BYTE packetData[1500];

/*Se initializeaza header-ul si ecb pentru receptia pachetelor*/

if((packetHeader=malloc(sizeof(IPXHeader)))!=NULL){
if((ecb=malloc(sizeof(ECB)))!=NULL)
IInitLisPacket(packetHeader,ecb,packetData,dim,targetSocket);
}
else
return(1); /* eroarea de alocare de memorie pentru header si ecb este 1*/

/* Se deschide socket-ul pentru receptionarea pachetului */


if(IPXOpenSocket( (void *)&sourceSocket, TEMPORARY_SOCKET))
{
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
free(packetHeader);
free(ecb);
return(2); /* eroarea de deschidere a socket-ului este 2*/
}
/* Are loc asteptarea pachetului*/

8
IPXListenForPacket( ecb );
while ( ecb->inUseFlag ){
IPXRelinquishControl();
if(bioskey(1)){
getch();
IPXCancelEvent( ecb );
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
free(packetHeader);
free(ecb);
return(3); /*eroarea 3 este break ,evita blocarea la transmisie */

}
}
if ( !ecb->completionCode ){
/*Daca mesajul nu e cel asteptat atunci functia va intoarce o valoare nenula si adresa de
unde s-a receptionat respectivul pachet*/
movmem(ecb->immediateAddress,packetAddress,6);
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
free(packetHeader);
free(ecb);
if (! memcmp(mesaj,packetData,dim))
return ( 0 ); /*functia intoarce 0 in cazul receptionarii pachetului
corect*/
else{
return ( 5 ); /* eroarea de receptionare a unui pachet diferit de cel asteptat
*/
}
else{
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
free(packetHeader);
free(ecb);
return(4); /*eroarea nr. 4 : pachetul nu a fost receptionat in bune conditii */
}
}

Posibilitatea de blocare a functiei este foarte mare in cazul unei functii de receptie ,daca la transmisie am
prevazut posibilitatea deblocarii prin apasarea unei taste doar pentru a putea opri procesul in cazul unei erori aici
aceasta posibilitate va elimina resetarea calculatorului in cazul unei blocari in receptie care devine o bucla infinita in
cazul in care nu soseste nici un mesaj ,acest lucru se poate intimpla foarte des la inceputul aplicarii algoritmului cind
inca nu este foarte bine pus la punct mecanismul de sincronizare.

Generalizarea acestei functii ,pentru receptionarea unui pachet oarecare de la o adresa care este apoi raportata
are urmatoarea organigrama:

9
Aloc spatiu pentru IPXHeader si ECB
|
Alocare corecta?--------NU-------intoarce 1
|
Deschide socket
|
Deschis corect?---------NU---elibereaza memoria
| |
| intoarce 2
|
Tasta apasata in timp ce primeste mesaj?------DA
| |
NU---------- Mesaj primit corect ? IPXCancelEvent()
| | |
elibereaza memoria elibereza memoria elibereaza memoria
| | |
inchide socket inchide socket inchide socket
| | |
intoarce 4 | intoarce 3
|
Intoarce 0 + adresa expeditor + pachet

Folosind aceasta functi se pot receptiona pachete de date de cite maxim 1500 de octeti iar prin receptionare in
bucla se pot receptiona pachete oricit de lungi.O problema foarte importanta care a fost lasata la latitudinea utilizatorului
dar care este foarte importanta la receptionarea mai multor pachete intr-o bucla este viteza de transmisie a lor .Lucrind
pe o retea locala sintem siguri ca primim pachetel in ordinea transmisiei lor dar si cu aceeasi viteza ,receptia ar trebui in
mod normal sa se faca pe mai multe socket-uri astfel incit IPX-ul sa nu trebuiasca sa astepte eliberarea buffer-ului
deoarece nu o poate face,deci pentru a putea receptiona toate pachetele e necesara o intirziere a pachetelor la
transmisie .Cel mai bine e ca initial aceasta viteza sa fie reglabila si se va adapta manual in functie de lungimea buclei
de receptie si bineinteles de viteza calulatoarelor,e bine ca in caeasta bucla sa nu se faca decit o reapelare a functiei de
receptie cu alt parametru de buffer ceea ce va face necesara o intirziere a pachetelor pe o retea de calculatoare 286
IBM PS/2 cu aproximativ 10 ms.

Acesta este functia cu parametri de apel buffer-ul in care va fi intoarsa adresa expeditorului ,buffer pentru
stocarea pachetului si dimensiunea pachetului:

int receivePacket(int *netaddress,char *packetData,int dim){

ECB *ecb; /* receive ecb */

IPXHeader *packetHeader; /* receive packet */

WORD sourceSocket=0x0050,targetSocket=0x0050;

/*Se initializeaza header-ul si ecb pentru receptia pachetelor*/

if((packetHeader=malloc(sizeof(IPXHeader)))!=NULL){
if((ecb=malloc(sizeof(ECB)))!=NULL)
IInitLisPacket(packetHeader,ecb,packetData,dim,targetSocket);
}
else
return(1); /* eroarea de alocare de memorie pentru header si ecb este 1*/

/* Se deschide socket-ul pentru receptionarea pachetului */


if(IPXOpenSocket( (void *)&sourceSocket, TEMPORARY_SOCKET))
{
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
free(packetHeader);
free(ecb);
return(2); /* eroarea de deschidere a socket-ului este 2*/

}
/* Are loc asteptarea pachetului*/

10
IPXListenForPacket( ecb );
while ( ecb->inUseFlag ){
IPXRelinquishControl();
if(bioskey(1)){
getch();
IPXCancelEvent( ecb );
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
free(packetHeader);
free(ecb);
return ( 3 ); /*eroarea 3 este break ,evita blocarea la receptie */

}
}
if ( !ecb->completionCode ){
memcpy(netaddress,ecb->immediateAddress,6 );
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
free(packetHeader);
free(ecb);
return ( 0 ); /*functia intoarce 0 in cazul receptionarii unui pachet corect*/

}
else{
IPXCloseSocket( sourceSocket );
/*Se elibereaza memoria alocata header-ului IPX si ECB-ului*/
free(packetHeader);
free(ecb);
return( 4 ); /*eroarea nr. 4 : pachetul nu a fost receptionat in bune
conditii */

}
}
Aceasta este generalizarea functie anterioare dezvoltind posibilitatile de realizare a legaturilor avind in vedere
ca intoarce si adresa de unde vine pachetul totusi este bine pentru o buna gestionare a resurselor sa se foloseasca
functia anterioara pentru sincronizare si crearea listelor de adrese si aceasta pentru receptionarea datelor. Nu este
obligatoriu ca datele sa fie transmise in salve chiar este indicat daca nu este necesar sa nu se transmita astfel ,pentru ca
va fi necesara intirzierea pachetelor pentru o buna receptie .
Daca transmisia s-ar fi facut sub SPX transmiterea in salve se impunea facindu-se economie de timp de
realizare a conexiunii,dar cum intr-o retea locala nu e necesara transmisia sub SPX pentru a avea aceleasi
facilitati(siguranta de atingere a destinatiei si ordinea pachetelor) am realizat aceste functii la un nivel 'inferior' cistigind
viteza si simplitate (nu mai este necesara realizarea unei conexiuni care necesita un schimb prealabil de pachete intre
expeditor si destinatar).
O functie suplimentara este functia de initializare cu care se incepe orice astfel de sistem distribuit. Functia de
initializare IPX este IPXInitialize() care trebuie apelata la inceputul oricarui program ce va folosi apeluri IPX.Functia care
am realizat-o este utila doar in masura in care programul lucreaza in mod text.Functia dupa ce face initializarea IPX va
afisa adresa de retea a calculatorului pe care o obtine cu functia IPXGetInternetworkAddress(buffer).Listing-ul acestei
functii este urmatorul:

void InitializareIPX(void)
{
int i;
unsigned char netaddr[10];

if ( ! IPXInitialize() )
printf( "\nIPX installed.\n"); /*initializarea a avut loc fara erori,exista
IPX.COM instalat in sistem. */
else {
printf( "\nIPX not installed. Program aborted." ); /*Nu se pot realiza
comunicatii IPX ,sriver-ul de retea nu a fost instalat */
exit( 1 );
}
IPXGetInternetworkAddress( netaddr ); /* Se obtine adresa de retea */
printf( "\nNetware Address : ");

11
for (i = 0; i < 4; i++ )
printf( "%02hX ",netaddr[i] );
printf( "\nNode Address : ");

for (i = 4; i < 10; i++ )


printf( "%02hX ",netaddr[i] );
printf("\n");
}

12