Instrukcja do laboratorium Systemów Operacyjnych (semestr drugi)

w

Ć iczenie dziesi t

ą e

Temat: Gniazda BSD – protoko y

ł internetowe

Opracowanie:

mgr in .

ż Arkadiusz Chrobot

Wprowadzenie

1. Us u

ł gi sieciowe w Linuksie

Gniazda BSD (nazwa pochodzi od wersji BSD Uniksa, istnieją również gniazda TLI pochodzące z Systemu V, ale nie są one używane w Linuksie) stanowią API dla

protoko ów

ł

komunikacyjnych

stosowane

we

wszystkich

systemach

operacyjnych, które umożliwiają pracę w sieci. W przypadku systemów uniksowych umożliwiają nie tylko pracę w

rodowisku

ś

rozproszonym, ale

również lokalną komunikację między procesami stanowiąc uzupełnienie wcze niej

ś

omawianych mechanizmów. Dzięki gniazdom można pracować z protoko ami

ł

należącymi do różnych dziedzin np.: Uniksa, Internetu i Xerox NS. Dodatkowo mo liwa

ż

jest praca zarówno z protokołami po czeniowymi, łą

jak

i bezpołączeniowymi.

2. Ró n

ż ice mi d

ę zy protokołem TCP i UDP

W dziedzinie Internetu aplikacje sieciowe wykorzystują najczęściej jeden z dwóch najpopularniejszych protokołów: TCP lub UDP. Za pomocą pierwszego dane są wysy ane

ł

w postaci strumienia. Ten protokół jest nazywany po czeniowym,

łą

gdyż nadzoruje przebieg transmisji dbając o retransmisję zagubionych i zniekształconych pakietów. Nie ma w nim ograniczenia na rozmiar wysy anych

ł

danych. W niektórych zastosowaniach mo e

ż

się jednak

okazać za wolny. Można wtedy zamiast niego zastosować protokół UDP. Jest on protoko em

ł

bezpołączeniowym. Jednorazowo można za pomocą tego protoko u ł

wys a

ł ć dane w wielkości mniejszej od 64KB. Protokół ten nie zapewnia retransmisji danych, a przypadki zniekształcenia lub zagubienia pakietów nale y

ż

obsługiwać samodzielnie. Jest on jednak zdecydowanie szybszy od protoko u

ł

TCP. Pakiety obu protoko ów

ł

są „opakowywane” w pakiety protoko u

ł

IP, st d najcz

ą

ciej w literaturze pojawiaj

ęś

si

ą

nazwy TCP/IP i UDP/IP.

ę

3. Serwery iteracyjne i wspó b

ł ie n

ż e

Aplikacje sieciowe można podzielić na dwie kategorie: klientów i serwery1.

1 W terminologii uniksowej nazywane demonami.

2

Zadaniem serwerów jest wykonywanie usług, o które proszą klienty2. Obs uga ł

żądań klientów mo e

ż

przebiegać w sposób sekwencyjny (iteracyjny) lub wspó bie

ł

ny.

ż

W pierwszym przypadku serwer nawiązuje po czenie łą

z klientem,

realizuje jego pro b

ś

,

ę wysy a

ł

odpowiedź i wraca do oczekiwania na po czenia

łą

z innymi klientami. Podczas realizacji żądania klienta aden ż

inny klient nie jest

w stanie połączyć się z serwerem. Serwer współbieżny po nawiązaniu po czenia

łą

z klientem tworzy proces potomny (w ogólnym przypadku wątek), który obs uguje

ł

prośbę klienta, a proces macierzysty oczekuje na połączenia od innych klientów.

4. Struktury danych

Strukturę wysy anych

ł

przez gniazdo danych, czyli protokół wy szego

ż

rzędu,

osadzony na protokole transmisji określa użytkownik. Aby jednak nawi za ą

ć

po czenie

łą

nale y

ż

zadeklarować i wypełnić odpowiednie pola zmiennej typu struct sockaddr_in.

5. Opis funkcji

W tym podrozdziale opisane zostaną tylko funkcje niezbędne do wykonania wi kszo

ę

ci

ś

zadań zawartych w instrukcji. Osoby, które chcą dokładniej zapoznać się z tematyką pisania oprogramowania dla sieci komputerowych powinny skorzysta z innych

ć

róde

ź

ł, jak np.: klasyczna już książka W. Richarda

Stevensa „Programowanie zastosowań sieciowych w systemie Unix”.

socket() – funkcja ta zwraca deskryptor gniazda poprzez które będzie odbywa a

ł

się komunikacja mi dzy

ę

stacjami roboczymi w sieci. Mo na

ż

o niej my le

ś ć jako o funkcji open przeznaczonej dla urządzeń sieciowych.

Pierwszy pobierany przez nią argument oznacza rodzinę protoko ów ł

(PF_INET dla protoko ów

ł

Internetu), drugi rodzaj gniazda (połączeniowe -

SOCK_STREAM, bezpo czeniowe

łą

- SOCK_DGRAM), natomiast ostatni

okre la

ś

którego konkretnie protoko u

ł

będziemy u ywa

ż

ć (w wypadku

protoko ów

ł

internetowych jest zawsze równy 0). Funkcja wykorzystywana jest zarówno przez oprogramowanie serwera jak i klienta. Szczegóły: man socket.

2 To nie literówka. W języku polskim wprowadzono dwie odmiany liczby mnogiej wyrazu „klient”, aby odróżni

ć ludzi od programów.

3

funkcja bind() – wyznacza gniazdu nazw .

ę Zazwyczaj wywołuje ją serwer

przed rozpoczęciem komunikacji z klientem, ale mo e ż

jej również u y

ż ć

klient celem zanotowania lub sprawdzenia adresu. Jako argumenty funkcja

pobiera

deskryptor

gniazda,

strukturę

zawierającą

adres

komputera (patrz: man unix, man 7 ip), oraz rozmiar tej struktury.

Szczegóły: man 2 bind.

funkcja connect() – jest wykorzystywana tylko przez klienta i służy do ustanowienia po czenia

łą

z serwerem w protokole po czeniowym.

łą

Pobiera

jako parametry: deskryptor gniazda, strukturę z adresem serwera i rozmiar tej struktury. Szczegó y: man connect ł

funkcja listen() – używana jest przez serwer pracujący z protoko em ł

połączeniowym do zgłoszenia

e

ż

będzie nasłuchiwał

da

żą

ń po czenia.

łą

Jeśli odbierze takie żądanie umie ci

ś

je w kolejce. Listen przyjmuje dwa

argumenty: deskryptor gniazda oraz liczbę żądań, które system mo e ż

umie ci

ś ć w kolejce zanim zostaną one zaakceptowane (szczegóły: man tcp).

Szczegóły: man listen.

funkcja accept() – jest wywoływana przez oprogramowanie serwera pracuj cego

ą

z

protoko em

ł

po czeniowym.

łą

S u

ł

y

ż

do

przyjmowania

połączeń. Wymaga trzech argumentów. Pierwszym jest deskryptor gniazda, drugim wskaźnik do struktury do której będzie zapisany adres klienta, a trzecim rozmiar tej struktury. Funkcja pobiera pierwsze żądanie z kolejki i tworzy dla niego gniazdo, o takich samych w a ł

ciwo

ś

ciach

ś

jak gniazdo,

do którego nadesz o

ł

danie.

żą

Jeśli kolejka jest pusta, to accept blokuje do

momentu, aż pojawi się w niej jakieś żądanie. Zazwyczaj gniazdo, którego deskryptor zwraca accept jest obsługiwane przez proces potomny.

Szczegóły: man 2 accept.

Funkcje read(), write() i close() – s u

ł żą do odbierania i zapisywania danych

w gniazdach je li

ś

obsługują one protokół połączeniowy. Dzia aj

ł ą one

trochę inaczej niż w przypadku plików. Jeśli przez gniazdo połączeniowe są wysyłane dane o rozmiarze przekraczającym rozmiar bufora (zazwyczaj 4KB), to wprawdzie są wysy ane

ł

jako jeden strumień, ale mogą ulec

segmentacji. Oznacza to, że funkcja read mo e

ż odebrać mniej danych, niż

okre lili

ś

my

ś

to w jej wywołaniu. Nie jest to b d,

łą

nale y

ż

po prostu

powtórzyć jej dzia anie.

ł

Po zako czeniu

ń

komunikacji nale y

ż

zamknąć

gniazda przy pomocy funkcji close niezale nie

ż

od tego jakim protokołem

się posługujemy.

4

Funkcja sendto() – s u

ł

y do wysy

ż

ania informacji przez gniazdo w protokole

ł

bezpołączeniowym. Przyjmuje sześć argumentów wywołania: deskryptor, wska nik

ź

na bufor wysy anych

ł

danych, rozmiar bufora, flagę (najczęściej

0), wskaźnik na strukturę w której zapisany jest adres przeznaczenia oraz rozmiar tej struktury. Zwraca liczbę przes anych ł

bajtów. Szczegóły: man

sendto.

Funkcja recvfrom() – s u

ł

y

ż

do odbioru danych z gniazda w protokole

bezpołączeniowym. Liczba i znaczenie argumentów jest podobne jak w przypadku funkcji sendto. Różnica polega na tym, że do bufora na dane są zapisywane odebrane informacje, a w przedostatnim argumencie zapisywany jest adres strony po czenia,

łą

która te informacje nada a.

ł

Szósty argument jest wska nikiem

ź

na zmienną i w niej jest zapisywana

wielkość odebranej struktury adresu. Funkcja ta blokuje działanie w oczekiwaniu na dane, jeśli nie zostały jeszcze wysłane.

Funkcje zmiany porz dku

ą

bajtów – porządek bajtów (big-endian) mo e

ż się

ró ni

ż ć od tego który jest u ywany

ż

w komputerze pod czonym

łą

do sieci.

Aby sobie z tą ró nica

ż

poradzić stworzono funkcje, które dokonują

odpowiedniej konwersji. Przy realizacji zadań przydatne b d ę

:

ą htons() (host

to network short) – do przeliczania numeru portu, htonl() (host to network long) do przeliczania adresu serwera, który mo na ż

domyślnie okre li

ś ć jako

INADDR_ANY oraz funkcja inet_addr(), która przekszta ca ł

adres w notacji

kropkowej (będący ciągiem bajtów) do 32-bitowego adresu internetowego.

Szczegóły: man inet_addr, man htons, man htonl

6. Kolejność wywo a

ł ń funkcji

Serwer

w

protokole

połączeniowym

wywołuje

opisane

wyżej

funkcje

w nast puj

ę

cej kolejno

ą

ci:

ś

socket() -> bind() -> listen() -> accept() -> (read(), write()) -> close() natomiast klient w nast puj

ę

cej:

ą

socket() -> connect() -> (write(), read()) -> close() Serwer w protokole bezpołączeniowym wywo uje

ł

funkcje w nast puj

ę

cej

ą

kolejno ci:

ś

socket() -> bind() -> (recvfrom(), sendto()) -> close() 5

natomiast klient w nast puj

ę

cej:

ą

socket() -> (sendto(), recvfrom()) -> close() Zadania

1. Napisz

program

do

przesyłania

prostych

komunikatów

między

dwoma

komputerami z u yciem protoko

ż

łu TCP/IP.

2. Napisz program, który będzie wysyłał komunikaty o rozmiarze przekraczającym 64KB mi dzy dwoma komputerami z u

ę

yciem protoko

ż

u TCP/IP.

ł

3. Napisz

program,

który

będzie

realizował

polecenie

zawarte

w

zadaniu

pierwszym, ale w oparciu o protokół UDP/IP.

4. Uzupe nij

ł

program

z

trzeciego

zadania

o

wykrywanie

i

retransmisję

zagubionych pakietów. Podpowied :

ź

można wykorzystać obsługę sygnałów,

w szczególno ci sygna

ś

SIGALRM.

ł

5. Stwórz serwer wspó bie

ł

ny,

ż

który b dzie

ę

obsługiwał po czenia

łą

od wielu

klientów, również napisanych przez Ciebie – mogą przesyłać np. losowe liczby do serwera, który b dzie je wy

ę

wietla

ś

na ekranie.

ł

6. Zamiast tworzyć w serwerze za każdym razem kiedy pojawi się danie

żą

od

klienta nowy proces można u y

ż ć funkcji select() (szczegó y:

ł

man select).

Zrealizuje zadanie pi te z u

ą

yciem w

ż

a

ł

nie tej funkcji.

ś

6