1. Aplikacje i Usługi Sieciowe

1.2. Architektura klient-serwer

Architektura klient-serwer jest podstawowym paradygmatem organizacji usług i komunikacji w nowoczesnych sieciach komputerowych. Jej podstawową ideą jest rozdzielenie funkcjonalności na dwie współpracujące jednostki: klienta, który inicjuje żądania i odbiera odpowiedzi, oraz serwera, który przetwarza te żądania i zwraca wyniki. Takie podejście pozwala na scentralizowaną kontrolę, lepsze zarządzanie zasobami, standaryzację interfejsów oraz skalowalność, która jest niezbędna w środowiskach o dużej liczbie użytkowników i operacji. Model klient-serwer leży u podstaw działania niemal wszystkich usług sieciowych: od WWW, przez pocztę elektroniczną, po bazy danych i aplikacje korporacyjne.

Rola klienta i serwera w tej architekturze jest jasno określona. Klient to oprogramowanie lub urządzenie końcowe użytkownika, które wysyła żądania do serwera w celu uzyskania konkretnej usługi lub zasobu. Może to być przeglądarka internetowa ładująca stronę WWW, program pocztowy wysyłający wiadomość, terminal logujący się do zdalnego systemu, aplikacja mobilna komunikująca się z interfejsem API. Klient nie musi przechowywać danych ani wykonywać złożonych operacji – jego główną funkcją jest inicjowanie i odbieranie danych. Serwer natomiast jest aplikacją nasłuchującą na konkretnym porcie i oczekującą na żądania od klientów. Może działać na dedykowanym sprzęcie lub jako instancja w chmurze. Serwer jest odpowiedzialny za przetwarzanie żądań, dostęp do danych, autoryzację, logikę biznesową, a czasem również generowanie wyników lub ich formatowanie.

Rysunek: schemat podstawowej architektury klient-serwer

Model klient-serwer zakłada, że połączenia są asymetryczne – klient aktywnie inicjuje komunikację, natomiast serwer pasywnie nasłuchuje. Działa to dobrze w środowiskach, gdzie dostępność i centralizacja usług mają znaczenie – przykładem może być bankowość elektroniczna, sklepy internetowe, systemy rejestracji pacjentów czy zarządzanie zasobami uczelni. Główne zalety tej architektury to centralizacja danych i kontroli, łatwa aktualizacja i konserwacja serwera, lepsza ochrona informacji (dane pozostają po stronie serwera), możliwość wdrożenia silnego uwierzytelniania oraz rejestrowania aktywności. Wady to potencjalna pojedyncza punkt awarii (Single Point of Failure), ograniczenia przepustowości serwera i problemy ze skalowalnością przy dużym natężeniu żądań.

Architektura klient-serwer może być jedno-, dwu- lub wielowarstwowa. W modelu jednowarstwowym klient i serwer działają na tym samym urządzeniu, co nie jest już popularne. Model dwuwarstwowy to klasyczny przykład – klient przesyła żądanie, serwer odpowiada. W architekturze trójwarstwowej pojawia się dodatkowa warstwa pośrednia – serwer aplikacji lub serwer logiki biznesowej, który pośredniczy pomiędzy klientem a serwerem danych. To pozwala lepiej rozdzielić odpowiedzialności, zwiększyć skalowalność i bezpieczeństwo. Czwarta warstwa może obejmować np. usługi chmurowe, replikację danych, load balancery czy systemy cache'ujące.

Rysunek: model trójwarstwowy

W komunikacji klient-serwer wykorzystywane są różne protokoły warstwy aplikacji, zależnie od funkcji. Dla WWW jest to HTTP/HTTPS, dla poczty – SMTP, POP3, IMAP, dla zdalnego dostępu – SSH, dla transferu plików – FTP, dla baz danych – SQL przez TCP. Protokoły te mają charakter tekstowy lub binarny, synchroniczny lub asynchroniczny. Klient wysyła komunikaty w formie zgodnej ze specyfikacją protokołu, serwer je analizuje i zwraca odpowiedź, również zgodnie z protokołem. Klient może również oczekiwać kodu statusu, który wskaże, czy operacja się powiodła, oraz danych wyjściowych.

Model klient-serwer może być również stanowy lub bezstanowy. HTTP w wersji pierwotnej był protokołem bezstanowym – każde żądanie było niezależne, serwer nie „pamiętał” wcześniejszych interakcji. Dla zapewnienia sesji konieczne było dodanie mechanizmów takich jak ciasteczka, tokeny lub sesje serwerowe. W modelu stanowym serwer utrzymuje informacje o kliencie pomiędzy żądaniami – np. zalogowany użytkownik, koszyk w sklepie, postęp formularza. To umożliwia tworzenie złożonych interfejsów użytkownika, ale wymaga zarządzania pamięcią i skalowaniem.

Architektura klient-serwer opiera się na idei rozdziału odpowiedzialności: klient jest odpowiedzialny za interakcję z użytkownikiem i prezentację, a serwer – za przetwarzanie i przechowywanie. W systemach rozproszonych takie podejście umożliwia rozdzielenie komponentów aplikacji i ich uruchamianie na różnych maszynach. Przykład może stanowić aplikacja mobilna, która jako klient korzysta z interfejsu REST API serwera backendowego, który łączy się z bazą danych w chmurze. Klient może działać offline, zbierać dane, synchronizować się przy połączeniu.

Innym przykładem są aplikacje webowe typu SPA (Single Page Application), w których klient w przeglądarce (HTML+JavaScript) komunikuje się z serwerem za pomocą żądań AJAX/REST, a logika renderowania i interfejsu jest po stronie klienta. Serwer udostępnia dane, autoryzuje dostęp, obsługuje zapytania i przechowuje historię. Taki model prowadzi do częściowego rozmycia granicy między klientem a serwerem – klient staje się „inteligentny” (thick client), a serwer uproszczony (thin server). Przeciwieństwem są tzw. dumb clients, które jedynie wyświetlają wynik.

Model klient-serwer ewoluował w kierunku mikrousług, gdzie każdy serwis jest serwerem wobec innych komponentów i klientem wobec bazy danych czy usług trzecich. Serwisy komunikują się często poprzez REST lub gRPC, korzystają z brokerów komunikatów (RabbitMQ, Kafka), a logika systemu oparta jest na kontraktach i API. W takim układzie relacja klient-serwer może być dynamiczna i wielokierunkowa – serwer jednej usługi jest klientem kolejnej.

Rysunek: komunikacja mikrousług

Kwestie synchronizacji, kolejkowania, buforowania i niezawodności mają ogromne znaczenie w architekturze klient-serwer. Klient może implementować retry, timeouty, asynchroniczne kolejki, a serwer – mechanizmy rozpraszania obciążenia (load balancing), replikację, mechanizmy failover i monitoring. Gdy klient nie otrzyma odpowiedzi, może uznać usługę za niedostępną i próbować później. Serwery często mają zdefiniowaną politykę przyjmowania połączeń – liczba jednoczesnych sesji, limity żądań, ochrona przed DDoS, throttling, cache’owanie odpowiedzi.

Architektura klient-serwer znajduje zastosowanie zarówno w prototypach, jak i dużych systemach korporacyjnych. Klientem może być lekka aplikacja IoT, a serwerem system SCADA. Klientem może być frontend Angulara, a serwerem Pythonowy FastAPI. W systemach ERP klient korzysta z interfejsu terminalowego lub przeglądarkowego, a serwer odpowiada za obliczenia finansowe, generowanie dokumentów, komunikację z drukarką i przesyłanie danych do banku. W edukacji serwerami są platformy e-learningowe jak Moodle, klientami przeglądarki uczniów, API mobilne, a także integracje z katalogami LDAP.

Z perspektywy bezpieczeństwa architektura klient-serwer wymaga rozważnego planowania: klient nie powinien mieć bezpośredniego dostępu do zasobów serwera, dane powinny być przesyłane z użyciem TLS, autoryzacja i uwierzytelnianie muszą być realizowane przez tokeny sesyjne, JWT lub OAuth2. Serwery muszą walidować dane wejściowe, logować zdarzenia, zapewniać kontrolę dostępu. Dodatkowo stosuje się reverse proxy, Web Application Firewall (WAF), mechanizmy rate limiting i sandboxing środowiska wykonywania kodu.

Z technicznego punktu widzenia klient-serwer to także model implementacyjny: aplikacje są rozwijane jako pary: frontend + backend, często w różnych technologiach. Klient w React, Vue, Flutter komunikuje się z backendem w Django, ASP.NET, Spring. Warstwa komunikacji oparta jest na JSON, XML, Protobuf. Interfejsy są dokumentowane przy pomocy OpenAPI lub GraphQL, testowane, wersjonowane. Klient może być sprzętowy (czytnik RFID), mobilny (tablet), desktopowy (aplikacja C#) lub webowy (HTML5).

Zasadniczą cechą tej architektury jest możliwość odizolowania aktualizacji, rozwijania i testowania klienta i serwera niezależnie. Backend może przejść refaktoryzację, migrację do innej bazy danych lub konteneryzację bez konieczności modyfikowania frontendu, o ile interfejs API pozostaje stabilny. Klient może z kolei oferować nowe funkcje, przejść na nową bibliotekę UI, zmienić wygląd i zachowanie, bez naruszania działania backendu. Ten podział obowiązków pozwala zespołom pracować równolegle, stosować DevOps i CI/CD.