Serwer


Programowanie aplikacji klient-serwer

Algorytmy i implementacja serwerów

Podstawowe typy serwerów

Iteracyjne bezpołączeniowe

Iteracyjne połączeniowe

Współbieżne bezpołączeniowe

Współbieżne połączeniowe

R = (N/2 + 1) TP

gdzie N - długość kolejki zgłoszeń.

TP MAX = 1/KR

gdzie:

K - liczba klientów, R - liczba zgłoszeń nadsyłanych przez pojedynczego klienta w ciągu sekundy.

Algorytm działania iteracyjnego serwera połączeniowego (TCP)

  1. Utwórz gniazdo i zwiąż je z powszechnie znanym adresem odpowiadającym usłudze udostępnianej przez serwer.

  2. Ustaw bierny tryb pracy gniazda, tak aby mogło być używane przez serwer.

  3. Przyjmij kolejne zgłoszenie połączenia nadesłane na adres tego gniazda i uzyskaj przydział nowego gniazda do obsługi tego połączenia.

  4. Odbieraj kolejne zapytania od klienta, konstruuj odpowiedzi i wysyłaj je do klienta zgodnie z protokołem zdefiniowanym w warstwie aplikacji.

  5. Po zakończeniu obsługi danego klienta zamknij połączenie i wróć do kroku3, aby przyjąć następne połączenie.

Ad 1. Do odwzorowania nazwy usługi na numer portu wykorzystuje się funkcję getservbyname. Jako adres IP należy podać wartość INADDR_ANY. Jest to stała symboliczna określająca tzw. adres wieloznaczny, zgodny .z każdym adresem IP przydzielonym komputerowi, na którym działa serwer.

Ad 2. Skonfigurowanie gniazda do pracy w trybie biernym realizowane jest przez wywołanie funkcji listen, która przyjmuje również argument określający długość wewnętrznej kolejki zgłoszeń związanej z gniazdem.

0x08 graphic
Ad 3. W celu pobrania z kolejki następnego zgłoszenia połączenia serwer wywołuje funkcję accept. Funkcja ta zwraca deskryptor gniazda przydzielonego nowemu połączeniu.

Algorytm działania iteracyjnego serwera bezpołączeniowego (UDP)

  1. Utwórz gniazdo i zwiąż je z powszechnie znanym adresem odpowiadającym usłudze udostępnianej przez serwer.

  2. Odbieraj kolejne zapytania od klientów, konstruuj odpowiedzi i wysyłaj je zgodnie z protokołem warstwy aplikacji.

Ad 2. Serwer bezpołączeniowy komunikuje się z klientami przy pomocy funkcji sendto i recvfrom. Ich składnia jest następująca (plik socket.h):

int sendto(int sockfd, char *buff, int nbytes, int flags, struct sockaddr *to, int adrlen);

int recvfrom(int sockfd, char *buff, int nbyes, int flags, struct sokaddr *from, int *adrlen);

Znaczenie argumentów:

Algorytm działania współbieżnego serwera bezpołączeniowego (UDP)

Proces macierzysty, krok 1.

Utwórz gniazdo i zwiąż je z powszechnie znanym adresem odpowiadającym usłudze realizowanej przez serwer. Pozostaw gniazdo w stanie nie połączonym.

Proces macierzysty, krok 2.

Odbieraj kolejne zapytania od klientów posługując się funkcją recvfrom; dla każdego zapytania utwórz nowy proces potomny, który przygotuje odpowiedź.

Proces potomny, krok 1.

Rozpoczynając działanie, przejmij określone zapytanie od klienta i przejmij dostęp do gniazda.

Proces potomny, krok 2.

Skonstruuj odpowiedź zgodnie z protokołem warstwy aplikacji i wyślij ją do klienta posługując się funkcja sendto.

Proces potomny, krok 3.

Wykonaj funkcje exit (proces potomny kończy więc działanie po obsłużeniu jednego zapytania).

Uwaga:

Z powodu znacznego kosztu operacji tworzenia nowego procesu potomnego niewiele jest współbieżnych realizacji serwerów bezpołączeniowych.

Algorytm działania współbieżnego serwera połączeniowego (TCP)

Proces macierzysty, krok 1.

Utwórz gniazdo i zwiąż je z powszechnie znanym adresem odpowiadającym usłudze realizowanej przez serwer. Pozostaw gniazdo w stanie nie połączonym.

Proces macierzysty, krok 2.

Ustaw bierny tryb pracy gniazda, tak aby mogło być używane przez serwer.

Proces macierzysty, krok 3.

Przyjmuj kolejne zgłoszenia połączeń od klientów posługując się funkcją accept; dla każdego połączenia utwórz nowy proces potomny, który przygotuje odpowiedź.

Proces potomny, krok 1.

Rozpoczynając działanie, przejmij od procesu głównego nawiązane połączenie (tzn. gniazdo przeznaczone dla tego połączenia).

Proces potomny, krok 2.

Korzystając z tego połączenia, prowadź interakcję z klientem; odbieraj zapytania i wysyłaj odpowiedzi.

Proces potomny, krok 3.

Zamknij połączenie i wykonaj funkcję exit. Proces potomny kończy działanie po obsłużeniu wszystkich zapytań od jednego klienta.

0x08 graphic

Funkcja select - zwielokrotnianie we/wy

SKŁADNIA

#include <sys/types.h>

#include <sys/time.h>

int select(int maxfdpl, fd_set *readfds, fd_set
*writefds, fd_set *exceptfds,
struct timeval *timeout);

OPIS

struct timeval

{

long tv_sec; /* sekundy */

long tv_usec; /* mikrosekundy */

};

W zależności od wartości argumentu timeout w działaniu funkcji select wyróżnić można trzy przypadki:

Funkcja select - zwielokrotnianie we/wy

/* zeruj wszystkie bity w fdset */

FD_ZERO(fd_set fdset);

/* umieść 1 w bicie dla fd w fdset */

FD_SET(int fd, fd_set *fdset);

/* zeruj bit dla fd w fdset */

FD_CLR(int fd, fd_set *fdset);

/* sprawdź bit dla fd w fdset */

FD_ISSET(int fd, fd_set *fdset);

> 0 - ogólna liczba deskryptorów spełniających określone warunki,

0 - upłynął czas oczekiwania zanim któryś z deskryptorów spełnił
określony warunek

-1 - błąd.

Algorytm działania jednoprocesowego, współbieżnego serwera połączeniowego

  1. Utwórz gniazdo i zwiąż je z portem o powszechnie znanym numerze odpowiadającym usłudze realizowanej przez serwer. Dodaj gniazdo do listy gniazd, na których są wykonywane operacje we/wy.

  2. Wywołaj funkcję select, aby czekać na zdarzenie we/wy dotyczące istniejących gniazd.

  3. W razie gotowości pierwotnie utworzonego gniazda, wywołaj funkcje accept, w celu przyjęcia kolejnego połączenia i dodaj nowe gniazdo do listy gniazd, na których są wykonywane operacje we/wy.

  4. W razie gotowości innego gniazda, wywołaj funkcję read, aby odebrać kolejne zapytanie nadesłane przez klienta, skonstruuj odpowiedź i wywołaj funkcję write, aby przesłać odpowiedź klientowi.

  5. 0x08 graphic
    Przejdź do kroku 2.

Porównanie serwerów

Operacja utworzenia gniazda biernego (1)

socket = passiveTCP(usługa, dkol);

socket = passiveUDP(usługa);

/*

*--------------------------------------------------------

* passiveTCP - utworz gniazdo bierne dla serwera
* używajacego protokolu TCP.

*--------------------------------------------------------

*/

#include "passivesock.h"

int passiveTCP(char *service, int qlen)

{

return passivesock(service, "tcp", qlen);

}

/*

*--------------------------------------------------------

* passiveUDP - utworz gniazdo bierne dla serwera
* używajacego protokolu UDP.

*--------------------------------------------------------

*/

#include "passivesock.h"

int passiveUDP(char *service)

{

return passivesock(service, "udp", 0);

}

Operacja utworzenia gniazda biernego (2)

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <stdlib.h>

#include <string.h>

#include <netdb.h>

u_short portbase = 0;/* przesuniecie bazowe portu dla
serwera nieuprzywilejowanego */

/*

*-------------------------------------------------------

* passivesock - ustaw gniazdo dla serwera uzywającego TCP
* lub UDP i przypisz mu adres

*-------------------------------------------------------

*/

int passivesock(char *service, char *transport, int qlen)

{

struct servent *pse; /* wskaznik do struktury opisu
uslugi */

struct protoent *ppe; /* wskaznik do struktury opisu
protokolu */

struct sockaddr_in sin; /* internetowy adres punktu
koncowego */

int s, type; /* deskryptor, typ gniazda */

memset(&sin, 0, sizeof(sin));

sin.sin_family = AF_INET;

sin.sin_addr.s_addr = INADDR_ANY;

/* Odwzoruj nazwe uslugi na numer portu */

if(pse = getservbyname(service, transport))

sin.sin_port = htons(ntohs((u_short)pse->s_port)

+ portbase);

else if((sin.sin_port = htons((u_short)atoi(service)))
== 0 )

exit(1);

/* Odwzoruj nazwe protokolu na jego numer */

if ( (ppe = getprotobyname(transport)) == 0)

exit(2);

Operacja utworzenia gniazda biernego (3)

/* Wybierz odpowiedni dla protokolu typ gniazda */

if (strcmp(transport, "udp") == 0)

type = SOCK_DGRAM;

else

type = SOCK_STREAM;

/* Utworz gniazdo */

s = socket(PF_INET, type, ppe->p_proto);

if (s < 0)

exit(3);

/* Przypisz adres gniazdu */

if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)

exit(4);

if (type == SOCK_STREAM && listen(s, qlen) < 0)

exit(5);

return s;

}

Implementacja iteracyjnego serwera bezpołączeniowego usługi TIME (1)

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <stdio.h>

#include <time.h>

#include <string.h>

#include ”passiveUDP.h”

extern int errno;

/* Roznica czasu między epoką UNIXa a epoka internetowa,
mierzona w sekundach */

#define UNIXEPOCH 2208988800

/*

*--------------------------------------------------------

* main - iteracyjny serwer UDP dla usługi TIME

*--------------------------------------------------------

*/

int main(int argc, char *argv[])

{

struct sockaddr_in fsin; /* adres klienta (nadawcy)*/ */

char *service = "time"; /* nazwa uslugi lub numer
portu */

char buf[1]; /* bufor wejsciowy niezerowej
długosci */

int sock; /* gniazdo dla serwera */

time_t now; /* czas biezacy */

int alen; /* dlugosc adresu nadawcy */

switch (argc) {

case 1:

break;

case 2:

service = argv[1];

break;

default:

fprintf(stderr, „Blad funkcji fork\n”);

exit(1);

}

Implementacja iteracyjnego serwera bezpołączeniowego usługi TIME (2)

sock = passiveUDP(service);

while (1)

{

alen = sizeof(fsin);

if (recvfrom(sock, buf, sizeof(buf), 0,

(struct sockaddr *)&fsin, &alen) < 0)

{

fprintf(stderr, „Błąd funkcji recvfrom !\n”);

exit(1);

|

time(&now);

now = htonl((u_long)(now + UNIXEPOCH));

sendto(sock, (char *)&now, sizeof(now), 0,

(struct sockaddr *)&fsin, sizeof(fsin));

}

}

Implementacja współbieżnego serwera połączeniowego usługi ECHO (1)

#include <sys/types.h>

#include <sys/signal.h>

#include <sys/socket.h>

#include <sys/time.h>

#include <sys/resource.h>

#include <sys/wait.h>

#include <netinet/in.h>

#include <sys/errno.h>

#include <stdio.h>

#include ”passiveUDP.h”

extern int errno;

/* definicje stalych */

#define QLEN 5

#define BUFSIZE 4096

int repear();

/*

*--------------------------------------------------------

* main - wspolbiezny serwer usługi ECHO

*--------------------------------------------------------

*/

int main(int argc, char *argv[])

{

char *service = "echo";` /* nazwa uslugi lub numer
portu */

struct sockaddr_in fsin; /* adres klienta */

int alen; /* dl. adresu klienta */

int msock; /* glowne gniazdo
serwera */

int ssock; /* gniazdo procesu
potomnego */

switch (argc) {

case 1:

break;

case 2:

service = argv[1];

break;

default:

Implementacja współbieżnego serwera połączeniowego usługi ECHO (2)

fprintf(stderr, "Sposob uzycia: TCPechod
[port]\n");

exit(1);

}

msock = passiveTCP(service, QLEN);

/* zainstalowanie procedury obslugi sygnalu SIGCLD */

signal(SIGCLD, repear);

while(1)

{

alen = sizeof(fsin);

ssock = accept(msock(struct sockaddr *) &fsin,
&alen);

if(ssock < 0)

{

if(errno == EINTR)

continue;

fprintf(stderr, "Blad accept\n");

}

switch(fork())

{

case 0: /*proces potomny */

close(msock);

exit(TCPechod(ssock));

case -1:

fprintf(stderr, "Blad fork !\n");

exit(1);

default: /* proces macierzysty */

close(ssock);

break;

}

}

}

Implementacja współbieżnego serwera połączeniowego usługi ECHO (3)

/*

*--------------------------------------------------------

* Funkcja TCPechod - wysylaj echo danych, skoncz po
* stwierdzeniu znaku konca pliku

*--------------------------------------------------------

*/

int TCPechod(int fd)

{

char buf[BUFSIZE];

int cc;

while(cc = read(fd, buf, sizeof(buf)

{

if (cc < 0)

{

fprintf(stderr, "Blad read\n");

exit(1);

}

if(write(fd, buf, cc) < 0)

{

fprintf(stderr, "Blad write\n");

exit(1);

}

}

return 0;

}

/*

*--------------------------------------------------------

* repear - procedura obslugi sygnalu SIGCLD

*--------------------------------------------------------

*/

int repear(void)

{

union wait status;

while(wait3(&status, WNOHANG, (struct rusage *)0) >=0)

; /* instrukcja pusta */

}

Implementacja jednoprocesowego, współbieżnego serwera usługi ECHO (1)

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/time.h>

#include <netinet/in.h>

#include <unistd.h>

#include <string.h>

#include <stdio.h>

#include "passiveTCP.h"

#define QLEN 5 /* maksymalna dlugosc kolejki popolaczen */

#define BUFSIZE 4096

/* Naglowki wykorzystywanych funkcji */

int echo();

void printerr(char *text);

/*

*--------------------------------------------------------

* main - wspolbiezny serwer TCP dla uslugi ECHO

*--------------------------------------------------------

*/

int main(int argc, char *argv[])

{

char *service = "echo"; /* nazwa uslugi */

struct sockaddr_in fsin;/* adres klienta */

int msock; /* gniazdo glowne serwera */

fd_set rfds; /* zbior deskryptorow plikow
do czytania */

fd_set afds; /* zbior deskryptorow plikow
aktywnych */

int alen; /* dlugosc adresu klienta */

int fd, nfds;

switch (argc)

{

case 1:

break;

case 2:

service = argv[1];

break;

Implementacja jednoprocesowego, współbieżnego serwera usługi ECHO (2)

default:

printerrr ("Sposob wywolania: TCPmechod
[port]\n");

}

/* Utworz bierne gniazdo */

msock = passiveTCP(service, QLEN);

nfds = getdtablesize();

FD_ZERO(&afds);

FD_SET(msock, &afds);

while (1)

{

memcpy(&rfds, &afds, sizeof(rfds));

if (select(nfds, &rfds, (fd_set *)0, (fd_set *)0,

(struct timeval *)0) < 0)

printerr("Blad select!\n");

if (FD_ISSET(msock, &rfds))

{

int ssock;

alen = sizeof(fsin);

ssock = accept(msock, (struct sockaddr *)&fsin,

&alen);

if (ssock < 0)

printerr("Blad accept!\n");

FD_SET(ssock, &afds);

}

for (fd=0; fd<nfds; ++fd)

if (fd != msock && FD_ISSET(fd, &rfds))

if (echo(fd) == 0)

{

close(fd);

FD_CLR(fd, &afds);

}

}

}

Implementacja jednoprocesowego, współbieżnego serwera usługi ECHO (3)

/*--------------------------------------------------------

* echo - odeslij echo danych w buforze, zwroc liczbe
* bajtow

*--------------------------------------------------------

*/

int echo(int fd)

{

char buf[BUFSIZE];

int cc;

cc = read(fd, buf, sizeof buf);

if (cc < 0)

printerr ("Blad read!\n");

if (cc && write(fd, buf, cc) < 0)

printerr ("Blad write!\n");

return cc;

}

/*--------------------------------------------------------

* printerr - sygnalizuj wystapienie bledu i zakoncz
* dzialanie procesu.
*--------------------------------------------------------

*/

void printerr(char *text)

{

fprintf(stderr, text);

exit(1);

}

11

3

Algorytmy i implementacja serwerów

0x01 graphic

0x01 graphic

0x01 graphic

0x01 graphic



Wyszukiwarka

Podobne podstrony:
serwer wydruku
5.1.13 Sieć klient-serwer, 5.1 Okablowanie sieci LAN
POM wyklad z 03 09 serwerix
DNS konfiguracja serwera
Po prostu wlasny serwer internetowy ppwsin
Książka Serwer Windows 2003 Podręcznik akademicki Rozdział 1
PlaceKadry instalacja serweraMSSQL
Konfiguracja serwera Apache, SSL w systemie GNU Linux
Definiowanie reguł postępowania dla serwera FireWall określających sposób dostępu do wybranych serwe
klient serwer
Rodzaje serwerów, edukacja i nauka, Informatyka
linu serwer
Wymagania bhp dla serwerowni, BHP, PORADY BHP
Serwery
Wbudowane funkcje serwera MySQL
WŁASNY SERWER FTP WINDOWS XP, ۞ Nauka i Technika, Informatyka, Systemy operacyjne, OS MS Windows, Si
Serwer terminalowy, informatyka-zbiór-2
serwery do counter strike1 6

więcej podobnych podstron