Serwer internetowy wbudowany w libgreattao i jego klient
20.04.2015 21:57
W tym wpisie chciałbym omówić serwer internetowy, który został wbudowany do biblioteki dynamicznego generowania UI(libgreattao) i jego klient(tao-network-clinet). Zarówno libgreattao, jak i tao‑network-client są mojego autorstwa i dostępne na SourceForge. Zarówno klient, jak i kod serwera są w stadium pre‑alpha, ale protokół komunikacji jest już raczej stabilny.
Wstęp
Pisanie klient, jak i serwer, w przypadku tych dwóch projektów jest raczej pozbawione sensu. gdyż oba projekty mogą pracować jako klient, jak i jako serwer. Protokół komunikacji jest w końcu taki sam, różnica w tych dwóch trybach polega jedynie na sposobie nawiązywania połączenia. Wymieniane komunikaty będą zawsze takie same, niezależnie czy jedno z prezentowanych rozwiązań pracuje jako klient, czy jako serwer.
Możliwość pracy w dwóch trybach wprowadzono po to, bym nie musiał tworzyć oddzielnej aplikacji proksy do tego, by klient mógł współpracować z wieloma aplikacjami serwerowymi(jedna aplikacja może w końcu uruchomić drugą). Takie podejście zmniejszyło nakład pracy wymagany do stworzenia możliwości pracy z wieloma aplikacjami, bo to klient może działać w trybie proksy, a prawdę pisząc, to ma dwa tryby proksy, gdyż jest aplikacją libgreattao. Skoro klient jest aplikacją libgreattao, to można go uruchomić jako serwer libgreattao, a do niego podłączyć kolejnego klienta. Można? Można, ale w ten sposób nie podłączymy klienta do wielu aplikacji serwerowych, poza wykorzystaniem dodatkowego serwera proksy.
Sposób działania
Cały protokół to po prostu przesyłanie żądań odpowiadających niektórym wywołaniom libgreattao ze strony serwera, a klient wysyła prośby o przesłanie plików, jak klasa okna czy plik graficzny, a także status operacji tworzenia okna. Istnieje też wymiana plików wybranych w dialogu otwarcia/zapisu pliku.
Jeżeli serwer pracuje w trybie serwera, to dla każdego połączenia uruchamia oddzielny proces. Natomiast klient pracujący w trybie serwera, dla akceptacji połączenia uruchamia oddzielny wątek, a dodatkowy wątek oczekuje połączenia.
Rozwiązanie różni się od GTK Broadway tym, że nie przesyłamy namalowanego okna, a dodatkowo nie wyświetlamy obrazu w przeglądarce internetowej. Od RDP różni się to tym, że nie przesyłamy rozkazów utworzenia kontrolek. Przesyłamy jedynie polecenia, jak utwórz okno danej klasy, ustaw string, podłącz zdarzenie pod numer na serwerze, itd.
Uruchomienie serwera dla aplikacji
By uruchomić serwer dla aplikacji potrzebujemy certyfikatu i klucza prywatnego. Jeżeli klucz prywatny został zaszyfrowany, to możemy podać klucz jako parametr. Dodatkowo możemy podać hasło, które będzie wymagane od klienta podczas nawiązywania połączenia. Musimy podać numer portu. Oto przykład:
nasza_aplikacja --tao-network-port 1026 --tao-network-certificate-path /home/My/nasz_certyfikat.pem --tao-network-priv-key-path /home/My/nasz_klucz.pem --tao-network-priv-key-password NASZE_HASŁO_DO_KLUCZA --tao-network-password NASZE_HASŁO_DO_POŁĄCZENIA
Oczywiście dwa ostatnie argumenty są opcjonalne. Hasło nie może przekraczać 255 znaków, co dotyczy także klienta.
Uruchomienie klienta
By uruchomić klienta, wystarczy go uruchomić, np. poprzez kliknięcie. Jeżeli nie przekazaliśmy żadnych argumentów w wierszu polecenia, to klient poprosi nas o nazwę hosta i numer portu, a następnie o hasło, jeżeli aplikacja serwera go wymagała. Możemy jednak się nie patyczkować i przekazać wszystkie argumenty z linii poleceń. Oto przykład:
tao-network-client --host locahost --port 1026 --password NASZE_HASŁO_DO_POŁĄCZENIA
Klient jako serwer proksy dla jednej aplikacji
Możemy także uruchomić serwer proksy, korzystając z klienta. Robimy to łącząc oba powyższe przykłady:
tao-network-client --host locahost --port 1026 --password NASZE_HASŁO_DO_POŁĄCZENIA --tao-network-port 1027 --tao-network-certificate-path /home/My/nasz_certyfikat.pem --tao-network-priv-key-path /home/My/nasz_klucz.pem --tao-network-priv-key-password NASZE_HASŁO_DO_KLUCZA --tao-network-password NASZE_HASŁO_DO_SERWERA_PROKSY
Co się zmieniło? Musieliśmy zmienić jedynie numer portu, bo proksy może być uruchomione na tej samej maszynie, co serwer. Nadaliśmy też inne hasło do serwera proksy, bo mieliśmy taki kaprys. Oczywiście oba hasła można pominąć - pierwsze, bo nas o nie poprosi podczas połączenia, a drugie, bo klient to aplikacja libgreattao, więc pytanie o hasło do aplikacji-serwera będzie zdalne.
Odwrócenie ról
Co jednak, gdy chcemy korzystać z wielu aplikacji? W tym celu musimy odwrócić rolę takiej aplikacji, i sprawić, by stała się klientem. By jednak umożliwić sobie na połączenie z tymi aplikacjami, to możemy uruchomić serwer proksy, jednak nieco innego rodzaju niż poprzedni. Taki serwer proksy będzie serwerem zarówno dla aplikacji libgreattao, jak i dla aplikacji klienckiej. Poprzedni sposób polegał na bycie klientem dla aplikacji dla libgreattao i serwerem dla aplikacji klienckiej, więc mogliśmy tylko uruchomić jedną aplikację. Robi się to w następujący sposób:
tao-network-client --wait-on-port 1030 --path-to-certificate /home/My/nasz_certyfikat --path-to-priv-key /home/My/nasz_klucz_prywantny --password-to-priv-key NASZE_HASŁO_DO_KLUCZA --password HASŁO_DLA_APLIKACJI_TAO --tao-network-port 1027 --tao-network-certificate-path /home/My/nasz_certyfikat.pem --tao-network-priv-key-path /home/My/nasz_klucz.pem --tao-network-priv-key-password NASZE_HASŁO_DO_KLUCZA --tao-network-password HASŁO_DLA_TAO_NETWORK_CLIENT
Widzimy, ze znowu wykorzystaliśmy fakt, że tao‑network-client jest aplikacją libgreattao. Jest jedna, poważna, wada takiego rozwiązania. Ponieważ na sztywno ustawiamy port w -‑wait-on-port, to możemy obsługiwać tylko jedno połączenie. W przyszłości planuję dodać możliwość generowania portu, więc będzie można obsłużyć wiele połączeń klientów. Warto zwrócić uwagę na parametr password i to, co on teraz oznacza. Obecnie nie oznacza on hasła, które zostanie przekazane aplikacji tao ale hasło, które powinno być przekazane przez aplikację tao.
Jak się jednak połączyć?
Są dwa sposoby. W tym nagłówku zaprezentuję jeden, a w kolejnym kolejny. Oto przykład:
TAO_CONNECT_TO_CLIENT_ON_HOST=nazwa_hosta TAO_CONNECT_TO_CLIENT_ON_PORT=1030 TAO_NETWORK_PASSWORD=HASŁO_DLA_APLIKACJI_TAO nasza_aplikacja
Dlaczego użyliśmy zmiennych środowiskowych? Bo aplikacja może odpalać inną aplikację, która musi znać numer portu i host do połączenia. Jeżeli jednak nasz certyfikat ma wady, to aplikacja odmówi połączenia. By to zniwelować, to musimy podać jeszcze jedną zmienną środowiskową. Oto przykład:
TAO_NETWORK_FORCE=1 TAO_CONNECT_TO_CLIENT_ON_HOST=nazwa_hosta TAO_CONNECT_TO_CLIENT_ON_PORT=1030 nasza_aplikacja
Dodaliśmy kolejną zmienną o nazwie TAO_NETWORK_FORCE.
Skoro jednak uruchamiamy serwer proksy
No właśnie. Skoro uruchamiamy serwer proksy, to mamy możliwość wystartowania programu przez tao_network_client. Oto przykład:
tao-network-client --wait-on-port 1030 --path-to-certificate /home/My/nasz_certyfikat --path-to-priv-key /home/My/nasz_klucz_prywantny --password-to-priv-key NASZE_HASŁO_DO_KLUCZA --password HASŁO_DLA_APLIKACJI_TAO --tao-network-port 1027 --tao-network-certificate-path /home/My/nasz_certyfikat.pem --tao-network-priv-key-path /home/My/nasz_klucz.pem --tao-network-priv-key-password NASZE_HASŁO_DO_KLUCZA --tao-network-password HASŁO_DLA_TAO_NETWORK_CLIENT --tao-app-command-line --command nasza_aplikacja
Tao_network_client automatycznie ustawi wszystkie potrzebne zmienne i uruchomi aplikację.
Ograniczenia
Obecnie tao_network_client jest w fazie pre‑alpha, więc nie należy oczekiwać cudów. Błąd w połączeniu klienta z jedną aplikacją tao wyłoży całego klienta. Dodatkowo nie mamy generowania numerów portów po stronie klienta, więc w trybie proksy-serwera nie obsłużymy więcej połączeń klientów niż jedno.
Pozostałe kwestie klienta
Można podać maksymalny rozmiar w bajtach pojedyńczego pobranego przez klienta pliku opcją -‑max-file-len, jak i sumę bajtów wszystkich pobranych plików opcją -‑max-files-len.
Programowanie
- By móc programować własnego klienta, to należy skorzystać z nagłówka libgreattao/network.h
- By obsługiwać pobieranie/wysyłanie plików wybranych w dialogach plików, należy korzystać z funkcji tao_open_file, tao_close_file i tao_release_file