Programowanie dla sieci SOCKET

Komentarze

Transkrypt

Programowanie dla sieci SOCKET
Komunikacja przez sieć z
wykorzystaniem biblioteki
WINSOCK
dr inż. Piotr Kaczmarek
Instytut Automatyki i Inżynierii Informatycznej
LAN
(Local Area Network)
Warstwa fizyczna
Podstawowe topologie:
-Gwiazda
-Magistrala
-Ring
Medium:
-UTP, optical fiber,
2.4GHz ...
Model ISO OSI
Warstwa fizyczna (physical layer)
Warstwa fizyczna: (physical layer)
Jest odpowiedzialna za transmisję strumienia bitów między węzłami sieci. Definiuje protokoły
opisujące interfejsy fizyczne, to jest ich aspekty: mechaniczny, elektryczny, funkcjonalny i
proceduralny. Do funkcji tej warstwy należą: sprzęgniecie z medium transmisji danych,
dekodowanie sygnałów, określanie zakresu amplitudy prądu lub napięcia i określanie parametrów
mechanicznych łączówek (kształtu, wymiarów i liczby styków) oraz inne kwestie związane z
transmisją bitów.
Warstwa łącza danych
Zapewnia niezawodne łącze pomiędzy sąsiednimi węzłami. Nadzoruje przepływ informacji przez
łącze i w związku z podatnością warstwy fizycznej na zakłócenia i wynikające stąd błędy oferuje
własne mechanizmy kontroli błędów w przesyłanych ramkach lub pakietach (CRC - Cyclic
Redundancy Check).
Adres MAC
MAC (ang. Media Access Control)



podwarstwa warstwy łącza danych (ang. Data Link Layer, DLL) w
modelu OSI
sprzętowy adres karty sieciowej Ethernet i Token Ring, unikatowy
w skali światowej, nadawany przez producenta danej karty podczas
produkcji.
Adres MAC (ang. MAC address) jest 48-bitowy i zapisywany jest
heksadecymalnie (szesnastkowo). Pierwsze 24 bity oznaczają
producenta karty sieciowej, pozostałe 24 bity są unikatowym
identyfikatorem danego egzemplarza karty. Na przykład adres
00:0A:E6:3E:FD:E1 oznacza, że karta została wyprodukowana
przez Elitegroup Computer System Co. (ECS) i producent nadał jej
numer 3E:FD:E1.
Mechanizmy wykrywania kolizji
CSMA/CD
(Carrier Sense Multiple Access with Collision Detect)
Metoda dostępu CSMA/CD została zastosowana
w takich sieciach jak:
•
Ethernet (IEEE 802.3),
•
IsoEthernet (IEEE 802.9)
•
Fast Ethernet (IEEE 802.3u) - rozszerzenie
802.3
•
(inna nazwa ISO 8802.3u) lub 100Base-T,
•
Gigabitowy Ethernet.
CSMA/CD
1)
stacja, która wykryje kolizję jako pierwsza, natychmiast
przestaje nadawać i wysyła charakterystyczny sygnał
zakłócający - tzw. jamming signal.
2)
Wszystkie pozostałe stacje usłyszawszy ten sygnał,
przerywają swoje transmisje na losowo wybrany przedział
czasu t. (Czas ten nie jest zupełnie losowy, jest bowiem
wyznaczany na podstawie odpowiedniego algorytmu, który
wykorzystuje 6-o bajtowy adres karty sieciowej.
Zabezpieczona jest wobec tego sytuacja, w której stacje
wylosowałyby tą samą chwilę na retransmisję.
CSMA/CD
3) Po tym czasie każda ze stacji, która brała udział w kolizji ponawia
próbę transmisji. Jeżeli znowu nastąpi kolizja, wówczas przedział
czasu, jaki stacja ma odczekać jest równy 2*t. Przy ponownej kolizji
czas ten ponownie jest podwajany.
4. Jeżeli 16 razy pod rząd stacja nie będzie w stanie przeprowadzić
transmisji z powodu ciągle występujących kolizji, wówczas kolejne
próby są zaniechane, a informacja o błędzie przekazywana jest do
wyższych warstw modelu ISO/OSI i ostatecznie dociera do
użytkownika.
Warstwa sieciowa (network layer)
Dostarcza środków do ustanawiania, utrzymania i rozłączania połączeń sieciowych miedzy
systemami otwartymi, w których rezydują komunikujące się aplikacje, i odpowiada, za obsługę
błędów komunikacji. Ponadto warstwa sieciowa jest odpowiedzialna za funkcje routingu, który
wyznacza optymalną pod względem liczby połączeń drogę przesyłania pakietu przez sieć.
TCP
(Transsmition Control
Protocol)
warstwa transpotrowa
• Ustala połączenie pomiędzy dwoma komputerami mającymi
wymieniać dane (połączenie wirtualne)
• Połączenie nie kończy się na interface sieci, sięga aż do
warstwy aplikacji (do określonego procesu uruchomionego na
komputerze
• Każdy komputer tworzy gniazdo (socket), a punkty końcowe
połączenia dołączane są do tegoż gniazda. Każde gniazdo
posiada adres nazwany (numer portu)
TCP komunikacja
• Dane są przesyłane
w segmentach TCP
(ramkach z 20bajtowym
nagłówkiem)
• Protokół zapewnia niezawodność transmisji (kontroluje
dostarczenie pakietu (potwierdzenia), oraz jego
poprawność (suma kontrolna)
• Pakiet jest dostarczany wyłącznie do adresata
• W pierwszej fazie żądanie połączenia musi być wysłane
przez nadawcę a uzyskanie połączenia potwierdzone przez
odbiorcę
UDP
(User Datagram Protocol)
warstwa transpotrowa
Protokół bezpołączeniowy, więc nie ma narzutu na nawiązywanie
połączenia i śledzenie sesji. Brak mechanizmów kontroli przepływu i
retransmisji.
Korzyści:
większa szybkość transmisji danych i brak dodatkowych zadań, którymi
musi zajmować się host posługujący się tym protokołem. Z tych
względów UDP jest często używany w takich zastosowaniach jak
wideokonferencje, strumienie dźwięku w Internecie i gry sieciowe,
gdzie dane muszą być przesyłane możliwie szybko, a poprawianiem
błędów zajmują się inne warstwy modelu OSI. Przykładem może być
VoIP lub protokół DNS.
UDP udostępnia mechanizm identyfikacji różnych punktów końcowych
(np. pracujących aplikacji, usług czy serwisów) na jednym hoście
dzięki portom. UDP zajmuje się dostarczaniem pojedynczych
INTER-NET
• połączenie wielu
sieci między
sobą
• Musi istnieć
sposób
komunikacji
miedzy różnymi
standardami sieci
• Należy określić
ścieżkę
przesyłania
danych
IP
(Internet Protocol)
• Dane z datagramów
sieci lokalnej są
wyłuskiwane i
umieszczane w ramkach standardu IP
• IP pozwala na określenie adresu hosta w innej sieci
• Protokół zapewnia efektywne przesyłanie pakietów, nie
pozwala jednak na kontrolę ich dostarczenia
• Określenie trasy przesyłania datagramu oraz translacja
pakietu IP z i na pakiet protokołu wykorzystywanego w
sieci lokalnej spoczywa na Routerach (traserach)
• Komputery w sieci lokalnej
mogą być adresowane na
podstawie adresu MAC
(Medium Acces Control)
karty sieciowej
• Do adresowania komputerów
w środowisku między
sieciowym stosuje się adres IP
(IPv4 przedstawiony obok)
• Do poszerzenia przestrzeni
adresowej stosuje się
CIDR(Classes Interdomain
Routing) lub IPv6 (z
16bajtowym adresem)
• Można również
wykorzystywać nazwy
domenowe (w sieci musi
istnieć server DNS (Domain
Name Server) tłumaczący
nazwę na adres IP komputera
Adresowanie
IP v6
- adres składa się z 128b liczby (zazwyczaj zapisuje się w
postaci 8x 16b wartości
- bloki złożone z 0 można pominąć zastępijąc je ::
Przykłady:
2001:0db8:0000:0000:0000:0000:1428:57ab
2001:0db8:0:0:0:0:1428:57ab
2001:0db8:0:0::1428:57ab
2001:0db8::1428:57ab
2001:db8::1428:57ab
IPv6 typy adresów
W adresacji stosuje się trzy typy adresów:
adresy unicast – identyfikujące pojedynczy interfejs;
pakiety, które są kierowane na ten typ adresu
dostarczane są tylko do odbiorcy
adresy multicast – identyfikujące grupę interfejsów (mogą
one należeć do różnych węzłów), pakiety wysyłane na
ten adres dostarczane są do wszystkich członków grupy
adresy anycast – podobnie jak adresy multicast,
identyfikują one grupę interfejsów, jednak pakiet
wysyłany na ten adres dostarczany jest tylko do
najbliższego węzła (węzeł ten jest wyznaczany przez
protokół rutingu)
Zakresy adresów
adresy lokalne dla łącza (link-local address) – są to adresy
wykorzystywane tylko do komunikacji w jednym segmencie sieci
lokalnej lub przy połączeniu typu point-to-point. Rutery nie
przekazują pakietów z tego rodzaju adresem. Z puli pozostałych
adresów wyróżniane są przez prefiks FE80::/10. Każdy interfejs musi
mieć przydzielony co najmniej jeden adres lokalny dla łącza, nawet
jeżeli posiada adres globalny lub unikatowy adres lokalny.
unikatowe adresy lokalne (unique local adress) – są to adresy będące
odpowiednikami adresów prywatnych wykorzystywanych w protokole
IPv4. Z puli pozostałych adresów wyróżniane są przez prefiks
FC00::/7. Od adresów lokalnych łącza odróżnia je także prefiks
rutingu.
adresy globalne (global unicast address) – widoczne w całym internecie,
są odpowiednikami adresów publicznych stosowanych w IPv4; wszystkie pozostałe
Adresy specjalne IPv6
::/128 – adres nieokreślony (zawierający same zera).
::1/128 – loopback, adres wskazujący na host lokalny.
::/96 – pula zarezerwowana dla zachowania kompatybilności z
protokołem IPv4 (pierwsze 96 bitów stanowią 0, pozostają 32 bity na
adresy w formacie IPv4).
::ffff:0:0/64 – jw., ale pozwala wykorzystywać komunikację według
protokołu IPv6 w sieci IPv4.
2001:7f8::/32 – pula zarezerwowana dla punktów wymiany ruchu, każdy
z nich dostaje jedną podsieć /48.
2001:db8::/32 – pula wykorzystywana w przykładach i dokumentacji –
nigdy nie będzie wykorzystywana produkcyjnie.
2002::/24 – adresy typu IPv6 do IPv4. Są to adresy wygenerowane na
podstawie istniejących, publicznych adresów IPv4, dostępne dla
każdego użytkownika.
Autokonfiguracja IPv6
Dla podsieci będących LAN-em przydzielana jest pula
adresów z maską /64, co umożliwia tworzenie
unikatowych adresów lokalnych dla łącza w oparciu o
numery sprzętowe MAC (IEEE 802).
Adres taki (dla adresu MAC 10:22:33:44:55:66) będzie
miał postać:
64bitowy_prefiks_sieci:1222:33FF:FE44:5566
Routing pakietów
TCP/IP
• Stanowi połączenie dwóch protokołów
• Umożliwia efektywne przesyłanie pakietów
między sieciami (IP) oraz zapewnia kontrolę i
niezawodność przesyłanie pakietów między
dwoma komputerami (TCP)
• Protokół ten działa również w sieciach lokalnych
w których komputery posiadają adresy IP.
• Mechanizm ten można również wykorzystywać do
komunikacji między aplikacjami uruchomionymi
na pojedynczym komputerze z wykorzystaniem
adresu loop back 127.0.0.1 (localhost)
TCP/IP w modelu OSI
- połączenie można ustanowić pomiędzy 2
dowolnymi hostami,
- połączenie jest tworzone pomiędzy dwoma
aplikacjami z których jedna pełni rolę
serwera (nasłuchuje i przyjmuje
połączenie) a drugi klienta (inicjującego
połączenie)
- serwer musi mieć publiczny adres IP lub
musi znajdować się w tej samej sieci
LAN co klient
- serwer prowadzi nasłuch (czeka na
zgłoszenia) na przypisanym mu porcie
Brak gniazd
Wykorzystanie gniazd
Gniazda – usługi
serwera
• Standardowo stosuje się gniazda (odpowiadające numerom telefonów) w celu
realizacji pewnych usług. Gniazda są identyfikowane przez ich numer,
aplikacja klienta może połączyć się z określonym gniazdem serwera 80 – httpd,
21 – ftp, powyżej numeru 1024 znajdują się gniazda z których mogą korzystać
inne aplikacje
• Połączenie z gniazdem można uzyskać przez wpisanie adresu IP i nr gniazda w
postaci xxx.xxx.xxx:gniazdo
Protokoły
Http: - port 80
Ftp: - port 21
Ssh: - port 22
Smtp: - port 25
Pop3: - port 110
Bezpieczeństwo
Pakiety danych mogą być przechwycone w
trakcie ich transmisji, co może skutkować
odczytaniem poufnych informacji
Szyfrowanie polega na zakodowaniu danych
po stronie klienta i rozkodowaniu ich po
stronie odbiorcy.
Do kodowania wykorzystuje się protokół
TSL/SSL oparty o klucz publiczny i
prywatny
Klucz prywatny i publiczny
(RSA)
Tworzenie klucza:
1. Wybieramy losowo dwie duże liczby
pierwsze p i q (najlepiej w taki sposób,
aby obie miały zbliżoną długość w
bitach, ale jednocześnie były od siebie
odległe wartościami - maksymalizuje to
bezpieczeństwo klucza)
2. Obliczamy wartość n = pq
3. Obliczamy wartość funkcji Eulera dla n:
φ(n)=(p-1)(q-1)
4. Wybieramy liczbę e (1 < e < φ(n))
względnie pierwszą z φ(n)
5. Znajdujemy liczbę d odwrotną do e mod
φ(n);
TSL/SSL
TLS (ang. Transport Layer Security) – rozwinięcie
protokołu SSL (ang. Secure Socket Layer),
zaprojektowanego pierwotnie przez Netscape
Communications Corporation. TLS zapewnia poufność i
integralność transmisji danych, a także uwierzytelnienie
serwera, a niekiedy również klienta.
Serwer wyposażony jest w certyfikat (CA) pozwalający na
jego jednoznacze zidentyfikowanie.
Przy nawiązywaniu połączenia klient otrzymuje klucz
publiczny do szyfrowania danych sesji.
Forwarding portów
Adresy w sieci LAN zazwyczaj
pochodzą z przestrzeni
adresowej przypisanej sieciom
prywatnym (komputery nie mają
publicznych adresów IP.
Możliwe jest jednak
przekierowanie ruchu z
pewnego portu na IP
publicznym na pewien
określony port komputera w
sieci LAN.
Dzięki temu można zadedykować
do konkretnej usługi osobny
komputer, bez konieczności
zwiększania puli publicznych
Publiczne IP
Prywatne IP
np. 172.16.0.2
Wirtualne sieci prywatne VPN
Udostępnienie na zewnątz
wszystkich zasobów sieci
lokalnej byłoby dużym
zagrożeniem bezpieczeństwa
Z drugiej stony udostępnienie tylko
niektórych usług (przez
forwardowanie portów) jest
również luką bezpieczeństwa I
nie umożliwia korzystanie z
wszystkich zasobów sieci.
Sieć wirtualna tworzy szyfrowany
tunel przez który komputer
znajdujacy się poza siecią LAN
może mieć dostę do wszystkich
zasobów tej sieci (otrzymuje
adres IP w sieci lokalnej)
Architektura
Klient-Serwer
• Architektura ta dotyczy
warstwy aplikacji
• Wszystkie zasoby zgromadzone
są na serwerze i są udostępniane
przez niego komputerom klientom wyłącznie w takim zakresie w jakim ich
potrzebują,
• Architektura ta umożliwia ograniczenie dostępu do pewnych zasobów,
hermetyzację
• W architekturze tej można stosować wolne komputery klientów z małą pamięcią
dyskową, ponieważ większość zadań wykonywana jest w obrębie serwera, zaś
komputer klienta służy wyłącznie do wyświetlania wyniku operacji
• Komunikacja między serwerem a klientami może odbywać się z wykorzystaniem
protokołu TCP/IP, lecz wymaga sprecyzowania interface’u komunikacji
Algorytm
komunikacji
• Serwer oczekuje na żądania klientów i
obsługuje je w określonej kolejności,
sam jednak nie inicjuje połączenia
• Należy ustalić (jeśli nie korzysta się ze
standardowego protokołu (np. http lub
ftp) w jaki sposób przekazywać żądania
do servera
• Należy ustalić jakie zadania leżą w
kompetencji servera a jakie klienta
• W celu aktualizacji swoich danych to
aplikacja klienta musi zgłaszać
odpowiednie żądanie
Interface
komunikacji
• Żądanie przesyłane do
serwera, wywołuje w
aplikacji działającej na
serwerze odpowiednią
funkcję, której argumentami
stają się dane przesłane przez
klienta
• Należy zdefiniować
wszystkie możliwe typy
żądań oraz dane przesyłane
przy każdym z tych żądań i
odpowiedzi serwera i
umieścić je w dwóch klasach
interface’u osobno dla
klienta i dla serwera
Przykładowa klasa interface’u
Pomiędzy klientem i serwerem przesyłane są dane opisane strukturą:
struct CSFRAME{
int ID;
long DataSize
void *Data
};
Strona klienta
Żądania:
ID
Opis
1
PrześlijAktualneDane
2
SprawdzDane
dane
NULL
dane do sprawdzenia (np. Wykonany ruch)
Strona serwera
Odpowiedzi servera
ID
opis
1
AkualneDane
2
Błąd
dane
Aktualne dane (np. plansza)
kod błędu
Interface - implementacja
• Po stronie serwera i klienta powinny znajdować się dwie
klasy które realizują komunikację
• Powinny one posiadać metody nazwane tak jak żądania
klienta (przesłanie żądania klienta wywołuje odpowiednią
funkcję na serwerze)
Strona klienta
class CClientInterface{
public:
CPlansza* PrzeslijAktualneDane();
int SprawdzDane(CPlansza* plansza)
private:
CSFRAME KomunikatOdebrany;
CSFRAME KomunikatWysłany;
};
Strona serwera
class CServerInterface{
public:
void OdbierzŻądanie();
CPlansza* PrzeslijAktualneDane();
int SprawdzDane(CPlansza* plansza
private:
CSFRAME KomunikatOdebrany;
CSFRAME KomunikatWysłany;
};
Interface – implementacja cd.
Strona klienta
CPlansza*
CClientInterface::PrzeslijAktualneDane()
{
KomunikatWyslany.ID=1;
KomunikatWyslany.DataSize=0;
KomunikatWyslany.Data=NULL;
WyslijDoServera(KomunikatWyslany);
OdbierzZSerwera(&KomunikatOdebrany);
if(KomunikatOdebrany.ID==1) return
KomunikatOdebrany. Data;
else return NULL;
}
int CClientInterface:: SprawdzDane(CPlansza*
plansza)
{
KomunikatWyslany.ID=2;
KomunikatWyslany.DataSize=sizeof(CPlansza);
KomunikatWyslany.Data=plansza;
WyslijDoServera(KomunikatWyslany);
OdbierzZSerwera(&KomunikatOdebrany);
return (int*) KomunikatOdebrany. Data;
}
Strona serwera
CPlansza* CServerInterface:: OdbierzŻądanie()
{
CPlansza *plansza;
int KodBladu;
CzekajNaDaneOdKlienta(&KomunikatOdebrany);
switch(KomunikatOdebrany.ID){
case 1: plansza=PrzeslijAktualneDane();
KomunikatWyslany.ID=1;
KomunikatWyslany.DataSize=sizeof(CPlansza);
KomunikatWyslany.Data=plansza;
case 2:
KodBladu= SprawdzDane(KomunikatOdebrany.Data)
KomunikatWyslany.ID=2;
KomunikatWyslany.DataSize=sizeof(int);
KomunikatWyslany.Data=&KodBladu;
}
WyslijDoKlienta(KomunikatWyslany);
}
Inicjalizacja WinSock
(klient/server)
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup( MAKEWORD(2,2),
&wsaData );
if ( iResult != NO_ERROR )
printf("Error at WSAStartup()\n");
Ten kod musi zostać wywołany jednorazowo przy
uruchomieniu aplikazcji wykorzystującej bibliotekę WinSock,
dodatkowo należy dołączyć plik nagłowkowy #include
"winsock2.h" i bibliotekę “WS2_32.lib”
Tworzenie nienazwanego
gniazda (klient/server)
// Create a socket.
SOCKET m_socket;
m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( m_socket == INVALID_SOCKET ) {
printf( "Error at socket(): %ld\n", WSAGetLastError() );
WSACleanup();
return;
}
Port stworzony przez klienta otrzymuje numer w chwili
połączenia z serwerem. Numer portu na którym serwer
nasłuchuje musi zostać przydzielony w następnym kroku
Połączenie z nazwanym portem
(serwer)
// Bind the socket.
sockaddr_in service;
service.sin_family = AF_INET;
Inet_addr(„IP”) przekształca
ciąg znaków zwierających adres
IP komputera do właściwej
postaci (IN_ADDR)
service.sin_addr.s_addr = inet_addr( "127.0.0.1" ); Do przypisania adresu można
service.sin_port = htons( 27015 );
if ( bind( m_socket, (SOCKADDR*) &service,
sizeof(service) ) == SOCKET_ERROR ) {
printf( "bind() failed.\n" );
closesocket(m_socket);
return;
}
rwnież wykorzystać nazwę hosta
(jeśli jest zarejestrowana w DNS:
gethostbyname( „www.w
p.pl”)
htons konwertuje numer portu
dany jako unsigned short na
numer w formacie standardu
TCP/IP (big-endian)
Po wywołaniu funkcji bind na
serwerze zostaje aktywowany
port o wybranym numerze
Serwer oczekuje na żądanie
klienta
// Listen on the socket.
if ( listen( m_socket, 1 ) == SOCKET_ERROR )
printf( "Error listening on socket.\n");
Serwer „nasłuchuje” na wybranym porcie (m_sock).,
drugi argument funkcji listen określa długość kolejki
zgłoszeń, dla aplikacji z wieloma klientami należy ją
ustawić na wartość >1
listen pozostaje zawieszona tak długo jak nie pojawi
się żądanie ze strony klienta
Połączenie klienta z serwerem (klient)
sockaddr_in clientService; clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
clientService.sin_port = htons( 27015 );
if ( connect( m_socket, (SOCKADDR*) &clientService,
sizeof(clientService) ) == SOCKET_ERROR) {
printf( "Failed to connect.\n" );
WSACleanup();
return;
}
Wywołanie connect powadzi do nawiązania połączenia z
serwerem zlokalizowanym pod określonym adresem
(clientService) i słuchającym na wybranym porcie (27015).
Serwer dla celu tego połączenia dedykuje odrębny port (jego adres
przypisany zostaje do m_sock). Port nasłuchu nie służy do
komunikacji z klientami a jedynie do nawiązania połączenia!!!
Akceptacja połączenia
przychodzącego (serwer)
// Accept connections.
SOCKET AcceptSocket;
printf( "Waiting for a client to connect...\n" );
while (1) {
AcceptSocket = SOCKET_ERROR;
while ( AcceptSocket == SOCKET_ERROR ) {
AcceptSocket = accept( m_socket, NULL, NULL );
}
printf( "Client Connected.\n");
break;
}
Po tym jak funkcja listen została przerwana przez żądanie ze strony
klienta, accept aprobuje połączenie i dedykuje dla niego nowy port
(AcceptSocket)
Wysyłanie i odbiór danych
(klient/server)
Odbiór danych:
#define BUFF_LEN 32
int bytesRecv = SOCKET_ERROR;
char recvbuf[BUFF_LEN] = ""; //bufor danych
//Odbiera dane i zapisuje je do bufora.
//Zwraca ilość odebranych bajtów (bytesRecv)
bytesRecv = recv( m_socket, recvbuf, BUFF_LEN, 0 );
Wysyłanie danych:
int bytesSent;
char sendbuf[] = „ten tekst zostanie wyslany”
bytesSent = send( m_socket, sendbuf, strlen(sendbuf), 0 );
Dla serwera należy zamiast m_sock wykorzystać port stworzony do
komunikacji z klientem AcceptSocket !!!!
Komunikacja raz jeszcze
WSAStartup(...)
socket(...)
WSAStartup(...)
socket(...)
bind(...)
listen(...)
connect(...)
accept(...)
send(...)
recv(...)
recv(...)
send(...)
Czarne strzałki wskazują miejsca, w
których powinny znaleźć się poszczególne
funkcje wykorzystywane do komunikacji
Czerwone strzałki pokazują przepływ
danych między klientem a serwerem
Obsługa wielu klientów w
architekturze klient-serwer
Opis problemu:
• Dostarczenie wielu użytkownikom tych samych danych
(synchronizacja)
• Równoczesna szybka obsługa wielu zgłoszeń
Możliwe rozwiązania:
• Multicasting lub broadcasting - serwer wsyła dane na adres
sieciowy, który jest traktowany jako adres wszystkich
komputerów
• Klienci co pewien określony czas żądają od serwera
aktualizacji danych (serwer obsługuje każdego z klientów
osobno)
Zwiekszenie efektywności obsługi
klientów
Dotychczasowy schemat (serwer)
• Serwer tworzy nazwane gniazdo 'GniazdoServera' za pomocą
funkcji bind
• Serwer tworzy kolejkę zgłoszeń za pomocą funkcji listen
• Serwer oczekuje (nasłuchuje) na porcie 'GanizdoServera' na
zgłoszenie się klienta i po jego zgłoszeniu tworzy za pomocą
funkcji accept noew gniazdo (m_socket) dedykowane do
komunikacji z tymże klientem
• Po przeprowadzeniu pojedynczej transakcji gniazdo klienta
jest zamykane a serwer wraca do pkt. nr 3
Zwiekszenie efektywności obsługi
klientów
Dotychczasowy schemat (klient)
• Klient tworzy gniazdo nienzawane (socket)
• Klient łączy się z serverem (connect)
• Klient wysyła / odbiera dane z serwera
• Klient zamyka gniazdo.
Ten schemat jest realizowany za każdym razem kiedy klient
chce wysłać/odebrać dane z serwera
Zwiekszenie efektywności obsługi
klientów
Nowy schemat (serwer)
•
Serwer tworzy nazwane gniazdo 'GniazdoServera' za pomocą funkcji bind
• Serwer tworzy kolejkę zgłoszeń za pomocą funkcji listen
• Serwer tworzy tablicę deskryptorów gniazd i dodaje do niego
'GniazdoServera'
• serwer przegląda tablicę deskryptorów gniazd i wybiera z niej gniazdo na
którym pojawiła się aktywność za pomocą funkcji select
• Jeśli aktywność pojawiła się na gnieździe 'GniazdoSerwera' oznacza to że
zgłosił się nowy klient. Wtedy serwer za pomocą funkcji accept tworzy
nowe gniazdo dedykowane do komunikacji z tym klientem i umieszcza je w
tablicy deskryptorów
• serwer odbiera/przesyła dane przez gniazdo klienta i wraca do pkt 4.
Zwiekszenie efektywności obsługi
klientów
Nowy schemat (klient)
• Klient tworzy gniazdo nienzawane (socket)
• Klient łączy się z serverem (connect)
• Klient wysyła / odbiera dane z serwera
• Aby ponownie wysłać dane klient realizuje pkt 3.
Punkty 1-2 realizowane sa jednorazowo, a stworzone gniazdo
może być wykorzystywane aż do czasu zakończenia
połączenia przez closesocket(.)
Zwiekszenie efektywności obsługi
klientów – kod serwera
//W kodze pominęto etap tworzenia gniazda nazwanego
fd_set TablicaGniazd, TablicaGniazdTest;
sockaddr_in sinRemote;
int nAddrSize = sizeof(sinRemote);
listen(GniazdoSerwera,5); //tworzy kolejkę
FD_ZERO(&TablicaGniazd); //czysci tablice gniazd
FD_SET(GniazdoSerwera,&TablicaGniazd); //dodaje gniazdo serwera do tablicy
gniazd
while(1){ //nieskonczona pęta serwera
TablicaGniazdTest=TablicaGniazd;
if (select(0, &TablicaGniazdTest, (fd_set*)NULL, (fd_set*)NULL, 0) > 0) {
//// Cos sie stalo na jednym z gniazd.
Zwiekszenie efektywności obsługi
klientów – kod serwera
if (FD_ISSET(GniazdoSerwera, &TablicaGniazdTest)) { //nowe połączenie
SOCKET sd = accept(GniazdoSerwera, (sockaddr*)&sinRemote,
&nAddrSize);
if (sd != INVALID_SOCKET) {
FD_SET(sd,&TablicaGniazd); //dodanie gniazda do tablicy
// Wyswietlenie adnych klienta
cout << "Accepted connection from " <<
inet_ntoa(sinRemote.sin_addr) << ":" <<
ntohs(sinRemote.sin_port) <<
", socket " << sd << "." << endl;
else {
cout<<”BLAD”;
return;
}}
Zwiekszenie efektywności obsługi
klientów – kod serwera
else{ //poszukiwanie gniazda na którym wystąpił ruch
for(int i=0;i<TablicaGniazdTest.fd_count;i++)
if(FD_ISSET(TablicaGniazdTest.fd_array[i],&TablicaGniazdTest)
{
SOCKET m_socket=TablicaGniazdTest.fd_array[i];
int odczytano=0;
ioctlsocket(m_socket,FIONREAD,&odczytano);
if(odczytano==0)
{
closesocket(m_socket);
FD_CLR(m_socket,TablicaGniazd);
}
}
Zwiekszenie efektywności obsługi
klientów – kod serwera
if(odczytano==0) //połączenie zamkniete
{
closesocket(m_socket);
FD_CLR(m_socket,TablicaGniazd);
}
else
{
recv(m_socket,.....)
send(m_socket,.....)
}
}//powrot do początku petli while(1)
class Cklient
{
char IP[16];
int port;
sRamka S;
sRamka R;
SOCKET m_socket;
public:
Cklient();
Cklient(char *_IP, int _port);
void SetIP(char *_IP, int _port);
void Connect();
void Send(sRamka *_S);
void Receive(sRamka *_R);
};
Przykładowa
klasa klienta
Wykorzystanie klasy
{
Cklient klient(“128.1.1.100”,2018);
klient.Connect();
Sramka R;
R.ID=1;
Klient.Send(&R);
Klient.Receive(&R);
}

Podobne dokumenty