Számítógép-hálózatok: Labor 2
Bevezetés a SOCKET programozásba – UDP kliens A gyakorlat célja:
Megismerkedni a Kliens-szerver modellel A kapcsolodási végpont fogalmának az elsajátítása Megismerkedni SOCKET API alapstruktúráival, (socket, sendto, recvfrom) UDP kliens megvalósítása (UDP visszhang kliens)
Elméleti bevezető:
1. ábra. Kliens-Szerver modell A G1 és G2, G3 hosztok (számítógépek) hálózaton szeretnének kommunkálni. Ahoz, hogy létre jöjjön közöttük a kapcsolat, bizonyos feltételeknek kell teljesülniük. Ilyen feltétel a fizikai kapcsolat létezése, valamint az egymás megértését biztosító protokoll. Abban az esetben, ha a G1 hoszton működő alkalmazás, szolgáltatásokat nyújt a G2, G3 hosztokon futó alkalmazásoknak a G1 hosztott szervernek nevezzük és a G2, G3-as gépeket klienseknek. Abban az esetben, ha a kapcsolatott a kliens gépek kezdeményezik, akkor Kliens-Szerver modellről beszélünk. Csatlakozó (SOCKET) Ahoz hogy létrejöjjön egy komunikáció szükségünk van A kommunikációs végpontok azonosítója a csatlakozó. A hozzá tartozó rendszerhívások megfelelnek a szolgáltatás elérési pontoknak. Ezeknek a segítségével kezelhetjük a kommunikáziót pl. kommunikációs csatorna kiépítése, adtaok küldése és fogadása.
Számítógép-hálózatok: Labor 2 Ahoz, hogy igénybe tudjuk venni a G1 által nyujtott szolgáltatásokat szükségünk van egy címre. Úgy ahogy a minden napi életben is a címeknek több része van Pl. Kossuth Lajos utca 12/5 szám úgy itt egy szolgáltatásnak a címe több részből tevödhet össze. Első lépésben el kell érjük a gépet, másodszor szükségünk van a protokoll típusára és végül szükségünk van a protokoll végpontjára. A másik fontos dolog amire szükségünk van egy szolgáltatás igénybe vételére az a protokoll. Ahoz hogy a szerver és a kliens komunkálni tudjon
Címzés Ahoz, hogy egy hálozati kommunikációt fel tudjunk építeni szükséges a hálózatban található hosztotok (pl. számítógépet) egyedi azonósítására. Ezt a célt szolgálja a hálózati architektúra különböző rétegeiben táláható címzési eljárások. A legalcsonyabb színten, az adatkapcsolati rétegben, található a MAC cím, egy egyedi azonósító amellyel a gyartó látja el a hálozati interfészeket (hálózati kártya, routerek kimeneti portjai). Ez a címzési mechanizmus nem támogatja a gépek gyors keresését egy nagyméretű hálózatban. Ezért igen fontos a hálózati rétegben található címzési mechanizmus. A mi esetünkben az Internet Protokoll (IP) által használt címzés, amely transzparensen (felsőbb színten nem kell vele foglalkozni) ráépül a MAC címzési mechanizmusra és biztosítja, hogy hatékonyan megtalálható legyen a címzet. Két szabvanáya van az IP címeknek az IPv4, amely egy 32 bites szám. Ennek a felhasználó barát formálya (Human readeble form) a pontokkal elválasztott négy 1-3-számjegyű szám 0 és 255 között (pl: 123.44.5.321). Ez napjaink legelterjedtebb hálózati szabványa. Az IPv6-os szabvány hivatott felvaltani az IPv4-et, amely egy 128 bites rendszert használ a címzéshez. Fontos megjegyezni hogy egy IP cím nem egy gépet azonósít hanem egy hálózati interfész kártyát. Erre még ráépül egy mechanizmus a szállítási rétegben, amely elosztja a bejövő forgalmat a kiallakított csatlakozások (SOCKET) típusa szerint, és egy 16 bites port (65536 port minden egyes csatlakozók típusra) szerint, amely lehetővé teszi, hogy egyidejüleg több azonos típusú kapcsolatot alakítsak ki egy hosztról más hosztokkal. Számábrázolás Két elterjedt számábrázolás használnak: az Intel gépek által használt a kisebb fontosságú bájt van hátul – little endian, valamint ennek a forditottja a nagyobb fontoságú bájt van hátul – big endian. A hálózati komunikáció a big endián számábrázolást használja és úgy hivatkozik rá, hogy hálózati bájt sorrend (Network order). A tovabbiakban a hoszt által használt számábrázolásra gép bájt sorrendjéként (Host order) hivatkozunk. A socket csomag megvalósításában rendelkezésunkre állnak konverziós függvények amelyek megvalósítják az átalakítást Host order-ből Network order-be és vissza. htonl() - 32 bites mennyiséget a gép bájt sorrendjéből átvált hálózati bájt sorrendbe htons() - 16 bites mennyiséget a gép bájt sorrendjéből átvált hálózati bájt sorrendbe ntohl() - 32 bites mennyiséget hálózati bájt sorrendből átvált a gép bájt sorrendjébe ntohs() - 16 bites mennyiséget hálózati bájt sorrendből átvált a gép bájt sorrendjébe
Számítógép-hálózatok: Labor 2
UDP Protokoll föbb tulajdonságai: Egy összekötetés nélküli protokoll, amely nem garanantálja a csomag célba megérkezését. A Winsock API programozása A Winsock API-nak öt különböző verziója van: 1.0, 1.1, 2.0, 2.1 és Winsock 2.2. A jelölési konvenciók az 1.1-es verziótól az, hogy a Winsock-hoz tartozó változók, makrók konstansok és függvények WSA előtaggal kezdődnek. A Winsock inicializálása Ahoz, hogy egy folyamatn belül inicializáljuk a Winsock-et (WinsockDLL) a int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData); függvényt kell meghívnunk. Az első paraméterben a magasabb helyértékű byte az igényelt fő verziószám, az alacsonyabb a mellék verzió. Ezt legegyszerűbben a MAKEWORD(x,y) makró alkalmazásával érhetjük el, ahol az x a magas, y az alacsony helyiértékű byte. Így például a MAKEWORD(2,2) számunkra megfelelő paraméter. A második paraméterben visszakapott WSAData struktúra felépítése a következő: typedef struct WSAData { WORD wVersion; WORD wHighVersion; char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYS_STATUS_LEN+1]; unsigned short iMaxSockets; //használaton kívül a 2 verziótól unsigned short iMaxUdpDg; //használaton kivül a 2 verziótól char FAR * lpVendorInfo; //használaton kivül a 2 verziótól } WSADATA, *LPWSADATA; Az első paraméter az a verziószám, amit használni fogunk, a második paraméter a legmagasabb rendelkezésre álló verzió. a többi paraméter egy része verziófüggő, és egyik sem különösebben érdekes számunkra. Socketek létrehozása A socketek számára Windows alatt egy külön típust hoztak létre: ez a SOCKET típus. Socketeket a WSASocket illetve a socket függvénnyel hozhatunk létre. A socket függvény deklarációja: SOCKET socket ( int af, int type,
Számítógép-hálózatok: Labor 2 int protocol );
Az első paraméter a címcsalád (address family). UDP és TCP socket számára ez AFX_INET. A második paraméter SOCK_STREAM, SOCK_DGRAM és SOCK_RAW lehet. Az utolsó paraméter a protokoll. A 2.2 táblázat mutatja a címcsalád, a típus és a protokollok közötti összefüggést.
Címcsalád Protokoll megnevezése Internet Protocol Internet Protocol Internet Protocol Internet Protocol
Típus megnevezése
Típus
AF_INET TCP SOCK_STREAM AF_INET UDP SOCK_DGRAM AF_INET Nyers Socket SOCK_RAW AF_INET ICMP SOCK_RAW 1 táblázat: Az Internet Protocol fajtái Win32 alatt
Ezek után, a táblázat alapján, könnyen létrehozhatjuk a kívánt fajtájú socketet.
Kommunikáció Winsock alatt Kapcsolat nélküli kommunikáció esetéen a küldésre használjuk a int sendto ( SOCKET s, const char FAR *buf, int len, int flags, const struct sockaddr FAR *to, int tolen );
függvényt, aminél a címzett paramétereit adjuk meg a to struktúrában Az üzenetek fogadásához használjuk int recvfrom ( SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR *from, int FAR *fromlen );
aminek az utolsó két paramétere a figyelő socket címe és annak hossza. struct sockaddr_in { short sin_family; u_short sin_port;
Protokoll
IPPROTO_IP IPPROTO_UDP IPPROTO_RAW IPPROTO_ICMP
Számítógép-hálózatok: Labor 2 struct in_addr sin_addr; char sin_zero[8]; };
A sin_family értéke IP esetén AF_INET, a sin_port a TCP port címe, a sin_addr pedig az IP cím.
Végül a program befejezése előtt meg kell hívni a WSACleanup() függvényt.
Feladat: Írjatok egy UDP kliensalkalmazást, amely megérdezi az időszervertől a pontos időt és kiírja a képernyőre. Időszerver protokollja: Ha kap egy csomagot (bármit tartalmazhat a csomag) akkor arra a címre ahonnan a csomag érkezett visszaküldi a pontos időt. Az alkalmazás szerkezete.
1. ábra. UDP Kliensalkalmazás szerkezete
Példaprogram:
Számítógép-hálózatok: Labor 2
#include <stdio.h> #include "winsock2.h" // Link with ws2_32.lib #pragma comment(lib, "Ws2_32.lib") void main() { WSADATA wsaData; SOCKET ClientSocket; sockaddr_in ServAddr; int Port =; char SendBuf[1024]; int BufLen = 1024; //--------------------------------------------// Initialize Winsock WSAStartup(MAKEWORD(2,2), &wsaData); //--------------------------------------------// Create a socket for sending data ClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //--------------------------------------------// Set up the ServAddr structure with the IP address of // the receiver (server) (in this example case "192.168.113.85") // and the specified port number. ServAddr.sin_family = AF_INET; ServAddr.sin_port = htons(Port); ServAddr.sin_addr.s_addr = inet_addr("IPCIM"); //--------------------------------------------// Send a datagram to the receiver printf("Sending a datagram to the receiver...\n"); sendto(, , , 0, (SOCKADDR *), ); //----------------------------------------------// Call the recvfrom function to receive datagrams // on the bound socket. printf("Receiving datagrams...\n"); recvfrom(, , , 0, (SOCKADDR *), ); // kiiratas //--------------------------------------------// When the application is finished sending, close the socket. printf("Finished sending. Closing socket.\n"); closesocket(SendSocket); //--------------------------------------------// Clean up and quit. printf("Exiting.\n"); WSACleanup(); return;
Számítógép-hálózatok: Labor 2 }
Kérdések: 1. Mi a visszatérítési értéke a sendto-nak? 2. Mikor ter vissza a recvfrom és mi a visszaterítési értéke? Könyvészet: [1]. A. Tanenbaum : Számítógéphálózatok. Bp., Panem Könyvkiadó, 2004. [2]. Buraga, S. - Ciobanu, G.: Atelier de programare în reţele de calculatoare. Iaşi, Polirom, 2001 [3]. http://www.iana.org/assignments/port-numbers [4]. http://msdn.microsoft.com/en-us/library/ms741416(VS.85).aspx