Skąd pomysł na projekt?
Za studenckich czasów, mieszkając „na pokoju”, korzystałem ze stacjonarnego komputera do oglądania filmów i seriali. Najwygodniejszym miejscem do tego było łóżko. Niestety, jak to często na Netflix’ie czy YouTube’ie bywa, po włączeniu odtwarzania należało wybrać jeszcze odpowiednie ustawienia (jak np. język napisów lub lektora albo rozdzielczość wideo) o czym oczywiście przypominałem sobie jak już byłem wygodnie ułożony na łóżku. Jedynym ratunkiem był smartphone, który zawsze gdzieś tam obok się znajdował. Akurat zbiegło się to z zadaniem wykonania projektu aplikacji na przedmiot Programowanie Sieciowe, więc pomysł był gotowy 😉 Dodatkowo chciałem zacząć zabawę z Xamarin Forms (ze względu na wieloplatformowość, która zawsze mnie ciekawiła).
Byłem świadomy, że istnieją takie rozwiązania jak TeamViewer albo Microsoft Remote Desktop, ale dla mnie był to przerost formy nad treścią. Natomiast inne podobne rozwiązania miały reklamy albo mikropłatności, więc to też nie było to czego potrzebowałem.
O aplikacji serwerowej
Pierwotnie na zaliczenie wykonałem prostą aplikację konsolową (v1.0.0.0) opartą o bibliotekę .NET Framework, która miała za zadanie otwierać port TCP i oczekiwać na połączenia klientów. Umożliwiała kontrolowanie myszki i klawiatury oraz uruchamianie stron internetowych (np. Netflix lub Youtube) w domyślnej przeglądarce.
Ze względu na zainteresowania w dziedzinie bezpieczeństwa IT postanowiłem uwzględnić ją w moim projekcie – w tym celu dodałem szyfrowanie symetryczne przesyłanych komend pomiędzy klientem a serwerem. W przypadku .NET Framework’a jest to bardzo proste i wygodne, bo wystarczy odszyfrować przesyłane bajty takim samym hasłem, które zostało wykorzystane do zaszyfrowania (kryptografia symetryczna; hasło jest definiowane przez samego użytkownika). Gdy wystąpi niezgodność w wykorzystywanym kluczu to biblioteka generuje wyjątek, który wystarczy obsłużyć. Nie jest to jeszcze idealne rozwiązanie, bo nadal aplikacja jest podatna na zjawisko powtarzania przechwyconych pakietów, ale szyfrowanie na pewno ogranicza możliwości atakującego.
Chciałem także zautomatyzować wyszukiwanie serwera w sieci, aby osoby mniej techniczne nie musiały weryfikować adresów IP wykorzystywanych komputerów. W tym celu wykorzystałem zestaw technik Zero Configuration Networking. Dzięki nim możliwe jest rozgłaszanie obecności serwera w sieci za pomocą pakietów UDP przesyłanych na porcie 5535. Działanie technik uzależnione jest od konfiguracji sieci (np. router’a), dlatego problemy z automatycznym wykrywaniem serwerów mogą być niezależne od mojej aplikacji.
Na pewno wadą aplikacji w pierwszej wersji było zamykanie połączenia po przesłaniu każdej komendy. Sprowadziło mnie to do zastanawiania się nad przejściem na transmisję UDP, ale okazało się, że wystarczy tylko nie zamykać połączenia, żeby uzyskać szybszą i nadal niezawodną transmisję.
W nowej wersji aplikacji serwera (v2.0.0.0) naprawiono tę wadę. W ramach aplikacji działają dwa wątki: TcpServer (odpowiedzialny za uruchomienie drugiego wątku oraz akceptację połączeń z nowymi klientami i usuwanie klientów z którymi nie ma już połączenia) i ConnectedClientsManager (odpowiedzialny za wykonywanie poleceń odbieranych od aplikacji klientów oraz sprawdzanie czy połączeni klienci nadal są obecni). Dzięki nim możliwe było zredukowanie opóźnień w wyniku braku potrzeby ciągłej akceptacji połączeń od klientów przy odbiorze każdego polecenia.
Dodatkowo w ramach nowej wersji opracowałem interfejs graficzny (wykorzystując bibliotekę WPF), który umożliwia korzystanie z aplikacji serwera w bardziej przyjazny dla użytkownika sposób. Inną wprowadzoną funkcją była możliwość minimalizacji aplikacji do zasobnika systemowego oraz dodawanie do systemowego autostartu. W oparciu o poradniki znalezione w Internecie opracowałem lokalizację dla języka angielskiego (język można zmienić w ustawieniach aplikacji – domyślnie wybierany jest na podstawie języka używanego w systemie operacyjnym). Oba tłumaczenia przechowywane są w postaci plików RESX.
Do opracowania instalatorów wykorzystałem system instalacyjny Inno Setup.
TODO
- Dodanie obsługi połączenia przez protokół UDP
- Dodanie zabezpieczenia przed powielaniem pakietów z poleceniami
O aplikacji klienta
Głównym wymaganiem w przypadku aplikacji klienta była obsługa systemu operacyjnego Android, aby sterować odtwarzaniem multimediów z poziomu posiadanego przeze mnie smartphone’a. Javą pobawiłem się trochę na początku studiów, ale niestety mnie nie urzekła. Bliżej mi było do języka C# ze względu na większe podobieństwo do poznanych wcześniej języków C/C++ i prostszą współpracę z systemem Windows. Na szczęście zawczasu dowiedziałem się o takim rozwiązaniu jak Xamarin Forms i wtedy postanowiłem nauczyć się programować w oparciu o ten framework. Dzięki temu opracowując kod dla systemu Android automatycznie otrzymywałem gotowy kod dla systemów Windows (UWP) i iOS (niestety ze względu na nieposiadanie żadnego urządzenia Apple nie miałem możliwości przetestowania aplikacji).
Aplikacja klienta pozwala na kontrolowanie myszki, klawiatury (tutaj musiałem użyć widget’u Entry, który domyślnie posiada tekst o długości jednego znaku zawierający spację i w przypadku zmiany zawartości generuje odpowiednio interpretowane zdarzenie), odtwarzania multimediów (wznawianie/zatrzymywanie odtwarzania, zmiana poziomu głośności, zmiana odtwarzanego utworu – operacje te udostępniane są poprzez bibliotekę user32.dll umożliwiającą kontrolę klawiatury) i otwieranie adresów stron WWW.
W ustawieniach aplikacji można wpisać parametry do połączenia z serwerem lub wyszukać dostępne serwery w sieci w oparciu zestaw technik Zero Configuration Networking.
Również w przypadku aplikacji klienta dodano lokalizację dla języka angielskiego. W przypadku, gdy język systemu operacyjnego to język polski, wtedy aplikacja klienta działa również w języku polskim. W każdym innym przypadku aplikacja klienta zostaje uruchomiona w języku angielskim. Również w tym przypadku tłumaczenia zostały oparte o pliki RESX.
TODO
- Dodanie zabezpieczenia przed powielaniem pakietów z poleceniami
- Zmiana biblioteki do wykrywania gestów dotyku
- Zmiana sposobu generowania komendy wciśnięcia prawego przycisku myszy
Jak używać aplikacji?
- Na początku należy pobrać najnowszą wersję aplikacji serwera w postaci instalatora (plik *.exe) z mojego Github’a.
- Po uruchomieniu aplikacji serwera na komputerze z systemem Windows należy udzielić zgody na połączenie sieciowe (w przypadku monitów od systemowego firewall’a).
- W ustawieniach aplikacji serwera należy ustawić numer portu oraz hasło potrzebne do komunikacji (domyślnie jest to port 22222 oraz puste hasło).
- Uruchomić serwer poprzez przycisk „Włącz serwer” w głównym oknie.
- Pobrać aplikację klienta z mojego Github’a (wersja dla systemu Windows [UWP] lub Android [plik *.apk]) lub ze sklepu Google Play (link na początku tego wpisu) i zainstalować na docelowym urządzeniu.
- Uruchomić aplikację klienta i w ustawieniach (ikona z zębatką) ustawić takie same parametry połączenia jak w przypadku serwera (numer portu i hasło; aplikacja klienta i serwera muszą się „widzieć”, czyli najczęściej muszą być uruchomione w tej samej sieci np. WiFi). Adres IP można wpisać ręcznie (jest to adres IP komputera z uruchomioną aplikacją serwera) lub wyszukać automatycznie (konfiguracja sieci może blokować poprawną pracę automatycznego wyszukiwania).
- Kliknąć przycisk „Połącz” w ustawieniach. W przypadku, gdy aplikacja klienta podczas próby połączenia wyświetla błąd, należy sprawdzić poprawność wprowadzonych parametrów połączenia. Czasami też połączenie może być blokowane przez konfigurację sieci lub firewall (zaporę sieciową) uruchomiony na komputerze (w takiej sytuacji należy sprawdzić konfigurację firewall’a lub go wyłączyć – jeżeli przy wyłączonym firewall’u wszystko działa poprawnie to należy zmodyfikować konfigurację zapory).
- O statusie połączenia informuje ikona w prawym górnym rogu na ekranie głównym w aplikacji klienta. W przypadku uzyskania połączenia, na ekranie głównym, możliwa jest kontrola kursora myszy (za pomocą gestów wykonywanych na szarym obszarze z symbolem myszki komputerowej oraz jednokrotnego tapnięcia dla LPM i dłuższego wciśnięcia obszaru dla PPM) oraz klawiatury. Kontroli multimediów oraz uruchamiania stron internetowych można dokonywać na stronie Skrótów.
W przypadku innych problemów z działaniem zapraszam do zgłaszania błędów w komentarzach lub na Github’ie 🙂 Jestem również otwarty na wprowadzanie nowych funkcji 🙂