Aplikacje wielowątkowe

Zaimplementuj serwer programu do komunikacji tekstowej (czat) obsługujący wielu klientów równocześnie. Każda aplikacja kliencka po połączeniu z serwerem ma możliwość wysyłania komunikatów, które następnie są przez serwer przekazywane do wszystkich pozostałych połączonych aplikacji klienckich. Przesyłanie komunikatów tekstowych pomiędzy serwerem a aplikacjami klienckimi odbywa się asynchronicznie z wykorzystaniem wielowątkowości.

Źródła:

  • szablon aplikacji serwerowej serwer.cpp
  • przykładowa aplikacja kliencka, którą można wykorzystać do testów czat_klient.cpp

Zaimplementuj następujące funkcjonalności:

  • Przycisk Run
    • tworzy gniazdo i ustawia je w trybie do nasłuchu.
    • tworzony główny wątek serwera, który oczekuje na połączenia
  • Główny wątek serwera:
    • w przypadku uzyskania połączenia tworzony jest wątek odpowiedzialny za obsługę danych nadchodzących od pojedynczego klienta.
    • w momencie przekroczenia dozwolonej liczby połączeń uniemożliwia nawiązanie połączenia z kolejnymi klientami
    • może być przerwany poprzez odpowiedni przycisk (np. ponowne wciśnięcie klawisza Run)
  • W przypadku nawiązania połączenia tworzony jest osobny wątek obsługujący to połączenie:
    • oczekuje na nadchodzące komunikaty
    • w przypadku otrzymania komunikatu rozsyła jego kopię do wszystkich połączonych z serwerem klientów
    • w przypadku zerwania połączenia zamyka gniazdo związane z tym połączeniem

Obsługa wątków:

Komunikacja sieciowa:

  • plik nagłówkowy winsock2.h i biblioteka WS2_32.lib
  • WSAStartup, WSACleanup()
    inicjalizacja WinSocket
  • socket, closesocket(), tworzenie gniazda
  • bind kojarzy gniazdo z lokalnym adresem
    sockaddr_in adres;
    adres.sin_port=htons(numer_portu);
    adres.sin_family=AF_INET;
    adres.sin_addr.s_addr=htonl(INADDR_ANY);
    bind(gniazdo, &adres, sizeof(adres));
  • inet_addr zamienia adres IP z postaci łańcucha znakowego do postaci liczby całkoiwtej
  • htons i htonl transfrormacja liczby short/long wymagana przy definiowaniu portu w protokole AF_INET i AF_INET6
  • listen() ustawia gniazdo w stanie nasłuchu
  • accept() ustanawia połaczenie, zwraca gniazdo łączące z klientem, pozwala na przesyłanie danych za pomocą send() i recv()
  • send() wysyła dane przez gniazdo
  • recv() odbiera dane z połacznoego gniazda