Aplikacje sieciowe i wielowątkowe
Zadanie 1 - Komunikator tekstowy z wilowątkowością
Zaimplementuj serwer programu do komunikacji tekstowej (czat) obsługujący połączenia w osobnych wątkach. Główny wątek serwera czeka na połączenie. W momencie uzyskania połączenia rozpoczyna odczyt kolejnych napływających komunikatów od klienta i umieszcza je w polu tekstowym (kontrolka edycyjna). Dodatkowo serwer umożliwia przesłanie do klienta komunikatu tekstowego umieszczonego w osobnym oknie edycyjnym. Aplikacja umożliwia zamknięcie połączenia (wraz z wątkiem głównym serwera) po wciśnięciu odpowiedniego przycisku. Wówczas ustawiane jest odpowiednie zdarzenie, które odebrane w wątku serwera powoduje zamknięcie gniazda nasłuchu i zakończenie wątku.
Ź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 rozpoczyna oczekiwanie na nadchodzące komunikaty tekstowe
- w przypadku otrzymania komunikatu umieszcza go w pierwszym (wejściowym) oknie edycyjnym
- w przypadku odebrania zdarzenia zamknięcia zamyka gniazda i kończy działanie wątku
- Przycisk
Send
- w przypadku gdy istnieje aktywne połączenie wysyła do klienta tekst umieszczony w drugim (wyjściowym) polu edycyjnym
Przydatne funkcje
Obsługa wątków:
- CreateThread tworzenie wątku
- TerminateThread przerywanie działania wątku
- CloseHandle zamyka uchwyt do obiektu (np. do wątku)
Synchronizacja wątków za pomocą zdarzeń
- CreateEvent tworzy uchwyt do obiektu zdarzenia
- SetEvent ustawia obiekt zdarzenia w stanie sygnalizującym zajście zdarzenia
- ResetEvent przywraca pierwotny stan zdarzenia
Komunikacja sieciowa:
- plik nagłówkowy
winsock2.h
i bibliotekaWS2_32.lib
- 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
- 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()
irecv()
- send() wysyła dane przez gniazdo
- recv() odbiera dane z połacznoego gniazda