Skocz do zawartości
  • 👋 Witaj na MPCForum!

    Przeglądasz forum jako gość, co oznacza, że wiele świetnych funkcji jest jeszcze przed Tobą! 😎

    • Pełny dostęp do działów i ukrytych treści
    • Możliwość pisania i odpowiadania w tematach
    • System prywatnych wiadomości
    • Zbieranie reputacji i rozwijanie swojego profilu
    • Członkostwo w jednej z największych społeczności graczy

    👉 Dołączenie zajmie Ci mniej niż minutę – a zyskasz znacznie więcej!

    Zarejestruj się teraz

[TuT] TCP w AutoIT. Część 1 - Podstawy, ISO/OSI, Sockety.


Rekomendowane odpowiedzi

Opublikowano

TCP w AutoIT: Podstawy i wysyłanie danych


Witam w pierwszym z serii moich tutoriali o TCP w AutoIT (i ogółem o TCP, UDP również tutaj poruszę ale w stopniu minimalnym), o tym jak go używać, z czym to się wiąże, co można zrobić, itepe itede.
 
Na początek wyjaśnię co to jest TCP, UDP, podstawowy model ISO/OSI i takie podstawowe terminy i duperele związane z przesyłaniem danych, a potem przejdę już do AutoITa.
 
Na początek coś o modelu OSI. Jest to model opisujący strukturę komunikacji sieciowej. Dzieli się on na 7 warstw, które są pokazane na poniższym rysunku:
 
zwode.jpg
 
Wygląda to tak. Jest siedem warstw, po obu "stronach" (klienta i serwera w naszym wypadku).
Warstwa fizyczna - Jest to warstwa najniższa, odpowiada za wysyłanie danych między klientem a serwerem - czyli ciągu zer i jedynek, na przykład przez USB, Bluetooth, Wifi, cokolwiek tego typu.
 
Warstwa łącza danych - Ona nadzoruje jakość przekazywania informacji przez warstwę fizyczną, oraz zajmuje się pakowaniem danych w ramki (oraz ich rozpakowywaniem) i wykrywaniem błędów związanych z niedotarciem danych lub uszkodzeniem ramek i ich naprawą. Ramka to dane + informacje dotyczące odbiorcy i nadawcy, czyli MAC nadawcy i odbiorcy, suma kontrolna CRC i informacje sterujące.
 
Warstwa sieciowa - Ona dysponuje wiedzą o topologii (budowie) sieci. Rozpoznaje jaką drogę przebywają dane wędrując przez sieć z serwera do klienta (trasowanie) i decyduje ile informacji należy przesłać danym połączeniem. Jeśli danych do przesłania jest za dużo to warstwa je po prostu ignoruje, nie musi zapewniać pewności i stabilności transmisji więc w razie błędu pomija niepoprawne pakiety danych.
Pakiet to zapakowane informacje, które wędrują przez sieć.
 
Warstwa transportowa - Ona segmentuje dane i składa je w strumień. Właśnie w tej warstwie są używane nasze protokoły - TCP oraz UDP. Warstwa ta zapewnia całościowe połączenie między serwerem a klientem która obejmuje całą drogę transmisji, dzieli je na części, które indeksuje (przydziela im numerki odpowiadające ich kolejności) i wysyła w sieć do klienta/serwera.
 
Wyższe warstwy tak naprawdę nas nie interesują, one są już tak jakby wbudowane w system operacyjny, po krótce - warstwa sesji utrzymuje sesję, synchronizuje dane pomiędzy aplikacjami i warstwami sesji systemu serwera i klienta, warstwa prezentacji zajmuje się przetwarzaniem danych tak, żeby niższe warstwy zawsze dostawały dane w tym samym formacie, odpowiada za kodowanie, konwersję oraz kompresję/dekompresję danych, ich szyfrowanie i deszyfrowanie a warstwa aplikacji to już sama aplikacja która nam te dane wyświetla, czyli na przykład przeglądarka internetowa albo nasz program.
 
Teraz trochę o samych protokołach TCP i UDP.
 
Protokół TCP (Transmission Control Protocol) to protokół trzeciej warstwy modelu OSI. Służy on do wysyłania danych pomiędzy komputerami. Jest on połączeniowy (czyli steruje wysyłanymi i odbieranymi danymi przez całą ich drogę), niezawodny i strumieniowy.
TCP gwarantuje wyższym warstwom komunikacyjnym dostarczenie pakietów w całości i po kolei, oraz bez duplikatów. To główny powód dla którego jest on najbardziej rozpowszechniony. Wysyłanie danych wygląda w nim w ten sposób:
- Serwer wysyła pakiet #1
- Klient odbiera pakiet #1
- Klient wysyła potwierdzenie dostarczenia pakietu #1
- Serwer odbiera potwierdzenie dostarczenia pakietu #1
- Serwer wysyła pakiet #2
[i tak dalej, i tak dalej]
 
Dzięki temu może sprawdzać czy wszystkie pakiety zostały odebrane, a w przypadku braku któregoś z nich może wysłać zapytanie o ponowne jego wysłanie. Dzięki temu mamy pewność że dane zostaną dostarczone w całości. Jedyną jego wadą jest to, że jest wolniejszy w stosunku do UDP.
 
UDP (User Datagram Protocol) to protokół bezpołączeniowy. W przeciwieństwie do TCP, nie kontroluje przepływu danych, ich kolejności, poprawności oraz tego czy dotrą wszystkie. Po prostu dane zostają wysłane do odbiorcy i jak dotrą - to będzie dobrze, a jak nie to nie ma to znaczenia dla UDP. Jest on jednak znacznie szybszy od TCP. Jest używany w sytuacjach, gdzie potrzeba szybkiego wysyłania danych a niekoniecznie trzeba te dane dostarczyć w 100%.
 
Komunikacja w TCP odbywa się metodą klient-serwer. To, oraz to że jest to protokół połączeniowy możemy zobaczyć w kodzie. Ale dosyć teorii, czas na praktykę.

Najlepiej będzie jeśli stworzymy sobie trzy pliki - klient.au3, serwer.au3 oraz run.au3. Po co nam ten trzeci? Nasze programy będziemy testować "na sucho", czyli w obrębie naszego komputera. A SciTE nie pozwala nam odpalać w trybie debugowania dwóch programów naraz, więc będziemy je kompilować (F7) i odpalać przy pomocy run.au3. Kod odpalania jest prosty.
 
Run("serwer.exe")
Run("klient.exe")
Zapisujemy wszystkie trzy skrypty w jednym folderze i przechodzimy do działania.

Najpierw napiszemy prosty serwer, który wyśle nam podane przez nas dane do klienta. Żeby użyć TCP musimy inicjalizować protokół. Służy do tego funkcja TCPStartup(). Protokół zamykamy funkcją TCPShutdown(). Narazie inicjalizujemy tylko TCP.

Na początek musimy serwer stworzyć. Służy do tego funkcja TCPListen
TCPListen(AdresIP, Port [, MaksymalnaKolejka])
AdresIP to adres IP w formacie xxx.xxx.xxx.xxx na którym uruchomimy nasz serwer
Port to port który będzie użyty do przesyłania naszych danych. Jest to zwykła cyfra, mieszcząca się w zakresie od 0 do 65535 (2^16-1). Z racji tego że porty od 0 do 1023 są określone jako ogólnie znane (używane przez podstawowe protokoły typu DNS, HTTP, FTP, XMPP, itp.) to używajmy tylko portów od 1024 w górę.
MaksymalnaKolejka to maksymalna ilość połączeń oczekujących na autoryzację. Parametr opcjonalny, narazie nam się nie przyda.

Funkcja ta zwraca uchwyt do socketa którego będziemy potem używać, więc musimy go zapisać do zmiennej, na przykład $serwer.

W razie błędu funkcja ustawia flagę błędu @error na 1 jeśli adres IP jest nieprawidłowy, 2 jeśli port jest nieprawidłowy lub parę innych kodów błędu z WinAPI - po szczegółowe ich kody zapraszam tutaj

Skąd mamy wiedzieć na jakim IP mamy uruchomić nasz serwer, skoro stawiamy go "lokalnie"? Posłuży nam do tego makro @IPAddress1 które nam zwróci "nasz" adres. Port jak mówiłem może być losowy w przedziale 1024 do 65535, my na przykład użyjemy 1337.

Jeszcze jeden szczegół - jeśli uda nam się utworzyć połączenie, musimy je też zamknąć. Służy do tego funkcja TCPCloseSocket


TCPCloseSocket(socket)
gdzie socket to zmienna z socketem który chcemy zamknąć. Tą funkcją zamykamy każdy socket jaki utworzyliśmy w programie. Bez zamykania socketa serwera, zamykanie programu wyglądałoby jak odłączenie prądu od komputera - dane niezapisane, pliki być może otwarte, wszystko szlag trafia bo system się nie zamknął.
TCPStartup() ;uruchamiamy TCP

Global $serwer = TCPListen(@IPAddress1, 1337)
If @ Then ;jeśli nastąpi błąd
	MsgBox(16, "Błąd!", "Nie mozna uruchomić serwera - kod błędu "&@)
	TCPShutdown() ;pamiętamy zeby wyłączyć TCP zanim wyjdziemy
	Exit
EndIf

TCPCloseSocket($serwer) ;zamykamy socket z serwerem
TCPShutdown() ;zamykamy TCP
Odpalamy program. Jeśli nic nam nie wyskoczyło (poza ewentualnym okienkiem z prośbą o odblokowanie AutoITa żeby mógł korzystać z sieci - wszystko jest okej. Jeśli jednak nastąpi jakikolwiek błąd to dla pewności możemy zmienić port na dowolnie inny i sprawdzić czy będzie wszystko działać.

No, mamy serwer. Teraz musimy coś zrobić żeby można było się z nim połączyć - samo odpalenie jego nie wystarczy. Serwer musi akceptować kolejne przychodzące połączenia i zapisywać sockety klientów. Do tego służy funkcja TCPAccept
TCPAccept(socketSerwera)
socketSerwera to uchwyt do socketa naszego serwera - czyli tego co zwróciła nam funkcja TCPListen. Funkcja ta sprawdzi czy do serwera nie chce się podłączyć żaden klient, jeśli tak - to go połączy. Jeśli nie to zwraca -1 lub kod błędu z WinAPI - i tutaj znowu kieruję do MSDN po szczegóły.
Żeby wszystko poprawnie działało, to należy tą funkcję wrzucić w pętlę żeby nasłuchiwała klienta dopóki on się nie połączy. Funkcja zwraca socket połączonego klienta. Dodajemy więc ją do kodu. Musimy również pamiętać żeby zamknąć socket klienta, jeśli uda nam się z nim połączyć - oczywiście zamykanie socketa klienta musi się odbyć wcześniej niż zamykanie socketa z serwerem. Inaczej, w bardziej złożonych aplikacjach, klient może na przykład nagle się zawiesić bo serwer nie odpowiada ale połączenie zakończone nie zostało.
TCPStartup() ;uruchamiamy TCP

Global $serwer = TCPListen(@IPAddress1, 1337)
If @ Then ;jeśli nastąpi błąd
	MsgBox(16, "Błąd!", "Nie mozna uruchomić serwera - kod błędu "&@)
	TCPShutdown() ;pamiętamy zeby wyłączyć TCP zanim wyjdziemy
	Exit
EndIf

Local $client ;zmienna w której będzie trzymany socket klienta

Do
	$client = TCPAccept($serwer)
	Sleep(100) ;sleep, dajmy procesorowi odpocząć
Until $client <> -1 ;dopóki funkcja zwraca -1, powtarzaj pętlę

MsgBox(64, "Info", "Klient się połączył!")

TCPCloseSocket($client) ;odłączamy klienta
TCPCloseSocket($serwer) ;zamykamy serwer
TCPShutdown() ;zamykamy TCP
No dobrze, ale nasz program będzie w ten sposób chodził w nieskończoność. Nikt nie będzie się próbował połączyć. Dlatego tutaj musimy już zacząć pisać kod klienta. Zaczynamy od TCPStartup i TCPShutdown na początku i końcu kodu, a pomiędzy nimi będziemy pisać kod klienta.
Od tego momentu przy kodzie serwera i klienta będzie odpowiedni komentarz na samej górze kodu, żeby się nikomu przypadkiem nie pomyliło :D

No to jedziemy z klientem. Najpierw musimy połączyć się z serwerem. IP oraz port muszą być podane takie same, jak przy tworzeniu serwera - w naszym przypadku będzie to również @IPAddress1 i 1337 (lub dowolny inny port, taki na jakim stworzyłeś serwer)

Do połączenie się z serwerem służy funkcja TCPConnect
TCPConnect(IP, port)
Parametry są proste. Funkcja zwraca socket serwera. W wypadku gdy coś pójdzie nie tak, ustawia @error (1 - IP nieprawidłowe, 2 - port nieprawidłowy, inne błędy
msdn.microsoft.com/en-us/library/ms740668.aspx
;############ NASZ KLIENT ############
TCPStartup()

Global $serwer = TCPConnect(@IPAddress1, 1337) ;próba połączenia z serwerem

If @ Then
	MsgBox(16, "Błąd!", "Nie udało się połączyć z serwerem - kod błędu: "&@)
	TCPShutdown() ;wyłączamy TCP
	Exit
EndIf

TCPCloseSocket($serwer) ;zamykamy socket serwera
TCPShutdown()
Bez odpalania serwera powinno nam wywalić błąd. A teraz skompilujmy oba skrypty i odpalmy przez nasze run.au3 (dodajmy sleepa pomiędzy nimi, sekunda dla pewności).

Jeśli wszystko zrobiliśmy dobrze - wyświetli się MsgBox z informacją że klient się połączył. Tak więc widzimy że wszystko działa jak powinno :D

W następnej części opiszę co i jak z wysyłaniem i odbieraniem danych. A narazie pozostaje czekać. Wszelkie pytania proszę zadawać tutaj, jeśli ktoś ma indywidualną sprawę - zapraszam na GG. Dziękuję za uwagę.

//przywróccie stare code i się z nim nie bawcie. już raz jak się bawił jakiś kretyn bez backupu to szlag trafił code w 90% moich tutów.
846331404756772371599.jpeg

Zarchiwizowany

Ten temat przebywa obecnie w archiwum. Dodawanie nowych odpowiedzi zostało zablokowane.

×
×
  • Dodaj nową pozycję...