1 / 47

Sistemsko programiranje

Sistemsko programiranje. IX. poglavlje Soketi kao sredstvo IPC. Ciljevi. Nakon svladavanja ovog poglavlja trebali bi znati : Razumjeti osnovne API funkcije za Windows Sockets Odrediti probleme portabilnosti između Berkeley-evih i Windows Socketa

feryal
Download Presentation

Sistemsko programiranje

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Sistemsko programiranje IX. poglavlje Soketi kao sredstvo IPC

  2. Ciljevi Nakon svladavanja ovog poglavlja trebali bi znati: • Razumjeti osnovne API funkcije za Windows Sockets • Odrediti probleme portabilnosti između Berkeley-evih i Windows Socketa • Koristiti Windows Sockete preko TCP/IP za peer-to-peer i klijent/server aplikacije • Uzeti u obzir promjene uvedne s Windows Sockets 2

  3. Dnevni red • 1. dio Uvod u WinSock • 2. dio Server (bind-listen-accept) • 3. dio Klijent • 4. dio Razmjena podataka • 5. dio Sažetak

  4. 1. dio Uvod u WinSock

  5. Windows Sockets (1/2) • Proširenje API-ja za Berkeley-eve Sockete • Prilagođeno za Windows okruženje • Portabilnost koda već ugrađena za Berkeley-eve Sockete • Windows stanice jednostavno integrirani u TCP/IP mreže • Izuzetci su kada su soketi tretirani kao opisnici datoteka • Pod UNIX-om • Također, proširene funkcije s prefiksom WSA

  6. Windows Sockets (2/2) • Funkcije koje manipuliraju s datotekama također rade sa socketima read() ioctl() write() close() • Ponašaju se kao Windows handleovi datoteka u načinu rada “overlapped” • Postoje i druge opcije mrežne komunikacije • Imenovane pipe • Remote Procedure Calls (RPC)

  7. Inicijalizacija WinSock DLL-a (1/2) int WSAStartup( WORD wVersionRequired, LPWSADATA lpWSAData); Za verziju može se koristiti Windows makro MAKEWORD(1,1) preko kojeg možemo zadati verziju i podverziju koja je u ovom primjeru 1.1

  8. Inicijalizacija WinSock DLL-a (2/2) • wVersionRequired • Određuje najvišu verziju WinSock DLL-a kojeg trebamo • Vraća vrijednsot različitu od nule ako DLL ne podržava verziju koju želimo • Niži byte određuje višu verziju • Viši byte određuje podverziju • 0x0202  verzija 2.2 • lpWSAData je pokazivač na strukturu WSADATA koja se popuni informacijama o konfiguraciji DLL-a • Pozvati WSAGetLastError() za određivanje broja pogreške

  9. Deklaracija i alociranje socketa (1/3) • Socketi su analgoni handle-ovima • Ali to je komunikacijski kanal • Pozivamo funkciju socket(...) kako bi kreirali (ili otvorili) socket • Zapravo HANDLE

  10. Deklaracija i alociranje socketa (2/3) • Server: socket koji “sluša” zahtjev za konekcijom od strane jednog ili više klijenata • Klijent: socket koji se spaja na nekog servera (hosta) koji je u stanju slušanja i koji će eventualno prihvatiti konekciju typedef unsigned int SOCKET; SOCKET socket(int af, int type, int protocol);

  11. Deklaracija i alociranje socketa (3/3) • af određuje familiju adresa • PF_INET ili AF_INET označava Internet protokol • type određuje način komunikacije koji može biti konekcijski orijentiran (SOCK_STREAM) ili ‘datagram’ komunikaciju (SOCK_DGRAM), tj. u ovisnosti od primjene biramo TCP ili UDP način komunikacije. • protocol neobavezno staviti za TCP/IP • Koristimo 0 socket vraća INVALID_SOCKET prilikom greške

  12. 2. dio Server (bind-listen-accept)

  13. Povezivanje (bind) (1/3) • Nakon stvaranja socketa, potrebno ga je povezati sa svojom adresom i određenim servisom int bind ( SOCKET s, const struct sockaddr *saddr, int namelen); • s je “nepovezani” SOCKET vraćen funkcijom socket() • saddr određuje familiju adresa i informacije specifične za protokol • namelen jeste sizeof(sockaddr) • Vraća SOCKET_ERROR u slučaju pogreške

  14. Povezivanje (bind) (2/3) SOCKADDR struktura struct sockaddr { u_short sa_family; char sa_data[14]; }; typedef struct sockaddr SOCKADDR, *PSOCKADDR;

  15. Povezivanje (bind) (3/3) • sa_data je specifično za određeni protokol • za TCP/IP koristimo specijalno sockaddr_in: struct sockaddr_in { short sin_family; // AF_INET u_short sin_port; struct in_addr sin_addr; //4-byte IP addr char sin zero [8]; }; typedef struct sockaddr_in SOCKADDR_IN, *PSOCKADDR_IN;

  16. Neka svojstva povezivanja • Lista hostova (mapirana na IP adrese) može se naći u %SystemRoot%\system32\drivers\etc\hosts • Lista servisa može se naći u datoteci %SystemRoot%\system32\drivers\etc\services • Ako se povežete na određenu adresu, možete primati dolazeće pakete samo preko te adrese • Ako imamo više od jedne IP adrese, povezuje se pomoću hotnl(INADDR_ANY)

  17. Primjer pripreme za povezivanje (1/3) BOOL WINAPI WNetGetHostAddress( LPCSTR lpszHost, LPCSTR lpszService, LPCSTR lpszProto, LPSOCKADDR lpAddr) /* Popunjava strukturu SOCKADDR koristeći ime hosta, protokola i servisa */ { LPHOSTENT lpHost; LPSERVENT lpServ; SOCKADDR_IN sin; ZeroMemory(&sin, sizeof(sin));

  18. Primjer pripreme za povezivanje (2/3) sin.sin_family = PF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); if(lpszHost != NULL) { lpHost = gethostbyname(lpszHost); if(lpHost != NULL) { CopyMemory(&sin.sin_addr, lpHost->h_addr_list[0], lpHost->h_length); } } lpServ = getservbyname(lpszService, lpszProto);

  19. Primjer pripreme za povezivanje (3/3) if(lpServ != NULL) { sin.sin_port = lpServ->s_port; ZeroMemory(sin.sin_zero, sizeof(sin.sin_zero)); CopyMemory(lpAddr, &sin, sizeof(SOCKADDR)); return TRUE; /* lpAddr je sada spremna za bind() */ } return FALSE; } Adresa vraćena pozivom WNetGetHostAddress(...) može se direktno upotrijebiti u bind() funkciji

  20. listen (...) • listen() omogućava serveru da prima konekcije klijenata • Socket prelazi iz stanja “povezan” u stanje “slušanja” int listen(SOCKET s, int nQueueSize); • nQueueSize pokazuje broj konekcijskih zahtjeva koliko želimo da čekaju u redu na konekciju • Najviše do SOMAXCON (5 za verziju 1.1, “neograničeno” kod verzije 2.0)

  21. accept (...) (1/2) • Poziv funkcije listen() stavlja socket u stanje slušanja • Aplikacija server poziva funkciju accept() • Vraća “konektirani socket” • accept() je blokirajuća funkcija i ona blokira sve dok ne dođe zahtjev za konekcijom od strane klijenta • accept() vraća vrijednsot koja daje serveru novi socket za razmjenu informacija

  22. accept (...) (2/2) SOCKET accept( SOCKET s, /* Socket koji je u stanju slušanja */ LPSOCKADDR lpAddr, /* Tu možemo naći detalje o klijentu */ LPINT lpnAddrLen /* Duljina vraćene strukture */ );

  23. 3. dio Klijent

  24. Strana klijenta (1/2) • Klijent koji se želi spojiti na server mora također deklarirati i kreirati socket pozivajući funkciju socket(...) • Ako socket nije povezan s adresom, Windows Socketi će mu pridjeliti jedinstvenu adresu koja će se koristiti prilikom trajanja konekcije

  25. Strana klijenta (2/2) int connect( SOCKET s, LPSOCKADDR lpName, int nNameLen); • lpName je pokazivač na strukturu SOCKADDR u kojoj je upisana adresa servera, a također i port na kojem server sluša

  26. Primjer aplikacije klijenta (1/2) #define S_IP “193.198.167.96” #define S_PORT 6784 main() { SOCKET sck; sockaddr_in s; // Startanje WinSock s WSAStartup(...) sck=socket(AF_INET,SOCK_STREAM,0); s.sin_family = AF_INET; s.sin_addr.s_addr = inet_addr( S_IP ); s.sin_port = htons( S_PORT );

  27. Primjer aplikacije klijenta (2/2) if (connect( sck, (SOCKADDR*) &s, sizeof(s) ) == SOCKET_ERROR ) { printf( ”Greška pri spajanju.\n" ); return; } printf( ”Uspješno spajanje na server.\n" ); .... // Tu dolazi komunikacija sa serverom }

  28. 4. dio Razmjena podataka

  29. Razmjena podataka (1/2) • Dvije strane koje komuniciraju razmjenjuju podatke koristeći funkcije send() i recv() • send() i recv() imaju jednake parametre: int send ( int recv ( SOCKET s, SOCKET s, LPSTR lpBuffer, LPSTR lpBuffer, int nBufferLen, int nBufferLen, int nFlags); int nFlags);

  30. Razmjena podataka (2/2) • nFlags == MSG_OOB označava hitnost • OOB znači “out-of-band” • MSG_PEEK može se koristiti ako hoćemo samo “pogledati” podatke bez da ih maknemo iz buffera • Ovo su standardni pozivi i kod Berkeley-evih Socketa • Ali, read() i write() su uobičajeni pod UNIX-om • Nisu “atomske” (da primaju byte po byte) niti su orijenitrane na poruke • Staviti u petlju dok se ne primi cijela poruka • Ili kod slanja, ali vrlo je rijetko da je send() nepotpun

  31. Datagram servis (1/2) • Strane razmjenjuju poruke koristeći sendto() i recvfrom() • Imaju iste parametre kao i send() i recv(), ali imaju dodatno još dva parametra s kojim se definira druga strana komunikacije int sendto ( int recvfrom ( SOCKET s, SOCKET s, LPSTR lpBuffer, LPSTR lpBuffer, int nBufferLen, int nBufferLen, int nFlags, int nFlags, LPSOCKADDR lpAddr, LPSOCKADDR lpAddr, int nAddrLen); LPINT pnAddrLen);

  32. Datagram servis (2/2) • Kod datagrama, nFlags parametar ne može biti MSG_OOB • Ne može se slati ili primati na hitan način • UDP (User Datagram Protocol), nekad U koristimo i kao Universal ili Unreliable.

  33. Zatvaranje socketa • Kod standardnih Berkeley-evih Socketa, pozivamo close() • Kod Windows Socketa pozivamo void closesocket(SOCKET s); • Za konekcijski orijenitranu komunikaciju, server zatvara samo socket kreiran s accept() • Ne onaj koji je vraćen od funkcije socket() • Samo onda kada se server u potpunosti gasi, onda treba zatvoriti socket koji sluša • Naposljetku, poziva se void WSACleanup(void); • Da prekinemo rad s WSOCK32.DLL • Ova funkcija također nije portabilna

  34. 5. dio Sažetak

  35. Sažetak rada sa socketima (1/2) Servis koji je konekcijski orijentiran (najčešće TCP) Server Klijent socket() socket() bind() connect() listen() accept() send()/recv() sendto()/recvfrom() closesocket() closesocket()

  36. Sažetak rada sa socketima (2/2) Bez stalne konekcije (Datagram) Server Klijent socket() socket() listen() connect() send()/recv() sendto()/recvfrom() closesocket() closesocket()

  37. Berkeley-evi vs Windows sockets • Standardni Berkeley-evi Socketi će biti portabilni s Windows Socketima, sa slijedećim iznimkama: • Mora se pozvati WSAStartup() kako bi inicijalizirali odgovarajući DLL • Iako se mogu koristiti UNIX-ovski read() i write() za primanje i slanje podataka, mora se prvo konvertirati Windows socket na handle operacijskog sustava pozivom _open_osfhandle() • Kod verzije socketa 1.1, također se mora pozvati setsockopt() kako bi prisilili sockete da se otvore kao handle-ovi koji nemaju “overlapped” svojstvo • Mora se koristiti closesocket() (ova funkcija nije portabilna), radije nego close() (koja jeste portabilna), kako bi zatvorili socket • Moramo pozvati WSACleanup() kako bi završili rad s DLL-om

  38. Overlapped I/O s Windows Socketima (1/2) • Kod WinSock 1.1, Windows otvaraju sockete kao preklapajuće (overlapped) datotečne handle-ove • Možemo dati socket kao parametar u ReadFile() ili WriteFile() bez ikakve modifikacije • Čekamo da operacije završe tako da ih pridružimo handle-u događaja (event handle) i pozivamo WaitForSingleObject() WaitForMultipleObjects() ili MsgWaitForMultipleObjects

  39. Overlapped I/O s Windows Socketima (2/2) • Koristimo I/O rutine za završavanje s ReadFileEx() / WriteFileEx() i proširene funkcije za čekanje WaitForSingleObjectEx(), WaitForMultipleObjectsEx(), i SleepEx() • Koristimo I/O port za završavanje s ReadFile() / WriteFile(), CreateIoCompletionPort(), i GetQueuedCompletionStatus()

  40. Windows Sockets 2 (1/2) • Windows Sockets 2, omogućeni u NT 4.0, dodaju još nekoliko područja funkcionalnosti • Primjedba: Koristiti 1.1 zbog razloga interoperabilnosti • Standardizirana podrška za preklapajući (overlapped) I/O • Rasprši/prikupi (Scatter/gather) I/O • Slanje i primanje iz ne-kontinuiranih memorijskih spremnika

  41. Windows Sockets 2 (2/2) • Mogućnost da zahtjevamo kvalitet usluge (QoS - quality of service) od sloja za podršku socketa • Brzina i pouzdanost kod prijenosa podataka • Mogućnost da organiziramo sockete u grupe • može se konfigurirati QoS za cijelu grupu socketa • to se ne mora raditi na bazi socket-po-socket • možemo uvesti prioritete za sockete koji pripadaju nekoj grupi • Višestruke konekcije (npr. konferencijski pozivi)

  42. Standardizacija preklapajućeg I/O (1/2) • Najvažniji dodatak kod Windows Socketa 2 je standardizacija preklapajućeg I/O • Socketi više nisu automatski kreirani kao preklapajući datotečni handle-ovi • socket() će kreirati ne-preklapajući handle • Ako želimo kreirati preklapajući socket, moramo pozvati WSASocket() i eksplicitno ga zahtjevati

  43. Standardizacija preklapajućeg I/O (2/2) SOCKET WSAAPI WSASocket( int iAddressFamily, int iSocketType, int iProtocol, LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags);

  44. Scatter/Gather I/O (1/4) • Kod WinSock 2 imamo dodatnu mogućnost da skupljamo i distribuiramo podatke za slanje ili primanje iz nekontinuiranih memorijskih spremnika (buffera) typedef struct WSABUF { u_long len; char *buf; } WSABUF, *LPWSABUF;

  45. Scatter/Gather I/O (2/4) • buf je pokazivač na podatke • len je broj byte-ova u tome spremniku • WSASend(), WSARecv(), WSASendTo(), i WSARecvFrom() koriste niz WSABUF struktura

  46. Scatter/Gather I/O (3/4) int WSARecv( SOCKET s, LPWSABUF lpRecvBuffers, DWORD dwBuffers, LPDWORD lpdwBytesReceived, LPDWORD lpdwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);

  47. Scatter/Gather I/O (4/4) • lpRecvBuffers je pokazivač na niz WSABUF struktura • dwBuffers je broj struktura u nizu • Kada podaci stignu, WinSock 2 driveri ih raspodijele po svim poslanim spremnicima

More Related