{"id":6203,"date":"2024-05-19T22:42:47","date_gmt":"2024-05-19T20:42:47","guid":{"rendered":"https:\/\/arduino.net.pl\/?p=6203"},"modified":"2024-05-20T13:50:14","modified_gmt":"2024-05-20T11:50:14","slug":"tutorial-korzystanie-z-gniazd-w-micropython","status":"publish","type":"post","link":"https:\/\/arduino.net.pl\/index.php\/tutorial-korzystanie-z-gniazd-w-micropython\/","title":{"rendered":"Korzystanie z gniazd w MicroPython. Tutorial"},"content":{"rendered":"\n<p class=\"has-sitebg-color has-accent-1-background-color has-text-color has-background has-link-color wp-elements-9bec711789262c58f7d6fa6e1796cd84\" style=\"font-size:24px;letter-spacing:3px\">Gniazda (ang. <em>sockets<\/em>) stanowi\u0105 podstaw\u0119 komunikacji przez internet. <br>Ten tutorial pokazuje, jak rozpocz\u0105\u0107 prac\u0119 z gniazdami, aby zaimplementowa\u0107 klient\u00f3w HTTP i HTTPS w j\u0119zyku MicroPython na mikrokontrolerach.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u0179r\u00f3d\u0142o:<\/strong> <strong>ESP32 In MicroPython: Client Sockets<\/strong>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.i-programmer.info\/programming\/148-hardware\/16596-esp32-in-micropython-client-sockets.html\" title=\"\">https:\/\/www.i-programmer.info\/programming\/148-hardware\/16596-esp32-in-micropython-client-sockets.html<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/arduino.net.pl\/wp-content\/uploads\/2024\/05\/6020ccd6-e1c5-4774-95be-7b528b22e2e6.jpeg\"><img decoding=\"async\" src=\"https:\/\/arduino.net.pl\/wp-content\/uploads\/2024\/05\/6020ccd6-e1c5-4774-95be-7b528b22e2e6.jpeg\" alt=\"gniazda, ptaki, druty\" class=\"wp-image-6228\"\/><\/a><figcaption class=\"wp-element-caption\">rys. Copilot Designer: Nests &amp; wires.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Tutorial<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Wprowadzenie<\/h3>\n\n\n\n<p>Je\u015bli chcesz wyj\u015b\u0107 poza prostego klienta, musisz skorzysta\u0107 z bardziej og\u00f3lnej metody po\u0142\u0105czenia sieciowego. Najcz\u0119stszym sposobem jest u\u017cycie \u201egniazd\u201d. Jest to szeroko wspierany standard internetowy i wi\u0119kszo\u015b\u0107 serwer\u00f3w obs\u0142uguje po\u0142\u0105czenia gniazdowe.<\/p>\n\n\n\n<p>MicroPython wspiera ograniczon\u0105 wersj\u0119 pe\u0142nego modu\u0142u Python Sockets. Cz\u0119\u015bci modu\u0142u, kt\u00f3re nie s\u0105 obs\u0142ugiwane, dotycz\u0105 g\u0142\u00f3wnie po\u0142\u0105cze\u0144 za pomoc\u0105 sieci nie-IP, wi\u0119c s\u0105 zazwyczaj ma\u0142o istotne.<\/p>\n\n\n\n<p>Najwa\u017cniejsze jest to, \u017ce gniazda s\u0105 bardzo og\u00f3lnym sposobem na nawi\u0105zanie dwukierunkowego po\u0142\u0105czenia mi\u0119dzy klientem a serwerem. Klient mo\u017ce utworzy\u0107 gniazdo do przesy\u0142ania danych mi\u0119dzy sob\u0105 a serwerem, a serwer mo\u017ce u\u017cy\u0107 gniazda do akceptowania po\u0142\u0105czenia od klienta. Jedyna r\u00f3\u017cnica mi\u0119dzy tymi sytuacjami polega na tym, \u017ce serwer musi albo sondowa\u0107, albo u\u017cywa\u0107 przerwa\u0144, aby wykry\u0107 now\u0105 pr\u00f3b\u0119 po\u0142\u0105czenia.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Tworzenie Obiekt\u00f3w Gniazd<\/h3>\n\n\n\n<p>Zanim b\u0119dziesz m\u00f3g\u0142 rozpocz\u0105\u0107 wysy\u0142anie i odbieranie danych, musisz utworzy\u0107 obiekt gniazda:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nimport socket\ns = socket.socket()\n<\/pre><\/div>\n\n\n<p>Ten domy\u015blny konstruktor tworzy gniazdo odpowiednie do po\u0142\u0105cze\u0144 IPv4.<\/p>\n\n\n\n<p>Je\u015bli chcesz okre\u015bli\u0107 typ tworzonego gniazda, musisz u\u017cy\u0107:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nsocket.socket(af=socket.AF_INET, type=socket.SOCK_STREAM, proto=socket.IPPROTO_TCP)\n<\/pre><\/div>\n\n\n<p>Parametr <code>af<\/code> okre\u015bla rodzin\u0119 adres\u00f3w i mo\u017ce by\u0107 albo <code>AF_INET<\/code> dla IPv4, albo <code>AF_INET6<\/code> dla IPv6 \u2013 w chwili pisania tylko IPv4 jest obs\u0142ugiwane. Parametr <code>type<\/code> wskazuje na <code>SOCK_STREAM<\/code> lub <code>SOCK_DGRAM<\/code>. Domy\u015blnie <code>SOCK_STREAM<\/code> odpowiada zwyk\u0142emu po\u0142\u0105czeniu TCP\/IP u\u017cywanemu do przesy\u0142ania stron internetowych i plik\u00f3w w og\u00f3le. Jest to po\u0142\u0105czenie trwa\u0142e i korygowane b\u0142\u0119dami, podczas gdy <code>SOCK_DGRAM<\/code> wysy\u0142a pojedyncze pakiety bez sprawdzania b\u0142\u0119d\u00f3w lub potwierdzenia, \u017ce dane zosta\u0142y odebrane. Ostatni parametr, <code>proto<\/code>, ustawia dok\u0142adny typ protoko\u0142u, ale poniewa\u017c obs\u0142ugiwane s\u0105 tylko <code>IPPROTO_TCP<\/code> i <code>IPPROTO_UDP<\/code>, jest to ustawiane zgodnie z parametrem <code>type<\/code>:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>type<\/th><th>proto<\/th><\/tr><\/thead><tbody><tr><td>SOCK_STREAM<\/td><td>IPPROTO_TCP<\/td><\/tr><tr><td>SOCK_DGRAM<\/td><td>IPPROTO_UDP<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Adresy Gniazd<\/h3>\n\n\n\n<p>Po zdefiniowaniu typu po\u0142\u0105czenia, musisz okre\u015bli\u0107 adresy zaanga\u017cowane w po\u0142\u0105czenie. Poniewa\u017c gniazda mog\u0105 by\u0107 u\u017cywane do \u0142\u0105czenia si\u0119 z r\u00f3\u017cnymi typami sieci, format adresu mo\u017ce si\u0119 znacznie r\u00f3\u017cni\u0107 i nie musi by\u0107 prostym URL-em lub adresem IP. Z tego powodu gniazda u\u017cywaj\u0105 w\u0142asnej wewn\u0119trznej reprezentacji adres\u00f3w i musisz u\u017cy\u0107 metody <code>getaddrinfo<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nsocket.getaddrinfo(host, port, af=0, type=0, proto=0, flags=0)\n<\/pre><\/div>\n\n\n<p>Pierwsze dwa parametry s\u0105 znajome i proste. Host musi by\u0107 okre\u015blony za pomoc\u0105 URL-a lub adresu IP. Drugi to numeryczny port do u\u017cycia z gniazdem. Kolejne trzy parametry s\u0105 takie same jak u\u017cyte do tworzenia gniazda. Generalnie u\u017cywasz tych samych warto\u015bci parametr\u00f3w dla adresu przeznaczonego do u\u017cycia z gniazdem jak te u\u017cywane do tworzenia gniazda. Je\u015bli nie okre\u015blisz parametru, <code>getaddrinfo<\/code> zwr\u00f3ci list\u0119 krotek dla ka\u017cdego mo\u017cliwego typu adresu. Ka\u017cda krotka ma nast\u0119puj\u0105cy format:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\n(af, type, proto, canonname, sockaddr)\n<\/pre><\/div>\n\n\n<p>gdzie <code>af<\/code>, <code>type<\/code> i <code>proto<\/code> s\u0105 takie jak wcze\u015bniej, <code>canonname<\/code> to kanoniczna nazwa dla typu adresu, a <code>sockaddr<\/code> to faktyczny adres, kt\u00f3ry r\u00f3wnie\u017c mo\u017ce by\u0107 krotk\u0105. W przypadku adresu IP, <code>sockaddr<\/code> to krotka w formacie:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\n(IP, port)\n<\/pre><\/div>\n\n\n<p>W chwili pisania, ESP32 obs\u0142uguje tylko IPv4 i zwraca tylko list\u0119 z jedn\u0105 krotk\u0105. Jedyn\u0105 naprawd\u0119 u\u017cyteczn\u0105 cz\u0119\u015bci\u0105 tej krotki jest ostatni element, kt\u00f3ry jest krotk\u0105 IP u\u017cywan\u0105 przez wi\u0119kszo\u015b\u0107 metod gniazd. Mo\u017cesz skr\u00f3ci\u0107 wszystko, po prostu tworz\u0105c krotk\u0119 IP i nie u\u017cywa\u0107 <code>getaddrinfo<\/code>. Jednak powiniene\u015b u\u017cywa\u0107 <code>getaddrinfo<\/code>, aby zapewni\u0107 kompatybilno\u015b\u0107 z pe\u0142nym modu\u0142em gniazd i na potrzeby przysz\u0142ego rozwoju.<\/p>\n\n\n\n<p>Na przyk\u0142ad:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nai = socket.getaddrinfo(&quot;www.example.com&quot;, 80, socket.AF_INET, socket.SOCK_DGRAM)\n<\/pre><\/div>\n\n\n<p>zwraca list\u0119:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\n&#x5B;(2, 1, 0, &#039;&#039;, (&#039;93.184.216.34&#039;, 80))]\n<\/pre><\/div>\n\n\n<p>a rzeczywist\u0105 krotk\u0105, kt\u00f3rej u\u017cywamy w wywo\u0142aniach metod gniazda, jest:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\n(&#039;93.184.216.34&#039;, 80)\n<\/pre><\/div>\n\n\n<p>Aby wyodr\u0119bni\u0107 t\u0119 ko\u0144cow\u0105 krotk\u0119, u\u017cywamy:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\naddr = ai&#x5B;0]&#x5B;-1]\n<\/pre><\/div>\n\n\n<p>Je\u015bli chodzi o adresy, istniej\u0105 dwie funkcje, kt\u00f3re mog\u0105 by\u0107 u\u017cywane do konwersji adresu IP w formie \u201ekropkowanej\u201d na warto\u015b\u0107 bajtow\u0105 i odwrotnie:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nsocket.inet_ntop(socket.AF_INET, bytes)\n<\/pre><\/div>\n\n\n<p>daje tekstow\u0105 form\u0119 kropkowan\u0105, a:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nsocket.inet_pton(socket.AF_INET, string)\n<\/pre><\/div>\n\n\n<p>daje binarn\u0105 form\u0119 adresu IP.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Gniazda Klienta w MicroPython<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Wprowadzenie<\/h3>\n\n\n\n<p>Gdy mamy obiekt gniazda i mo\u017cliwo\u015b\u0107 okre\u015blenia adresu, musimy po\u0142\u0105czy\u0107 go z innym gniazdem, aby stworzy\u0107 dwukierunkowy kana\u0142 komunikacyjny. Dane mog\u0105 by\u0107 zapisywane i odczytywane w obu gniazdach, kt\u00f3re tworz\u0105 po\u0142\u0105czenie. Dok\u0142adny spos\u00f3b po\u0142\u0105czenia gniazd zale\u017cy od tego, kt\u00f3re jest klientem, a kt\u00f3re serwerem. W tej sekcji zajmiemy si\u0119 tym, jak po\u0142\u0105czy\u0107 si\u0119 z serwerem. Domy\u015blnie wszystkie metody gniazd s\u0105 blokuj\u0105ce. P\u00f3\u017aniej om\u00f3wimy dzia\u0142anie nieblokuj\u0105ce.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Po\u0142\u0105czenie Gniazda Klienta z Gniazdem Serwera<\/h3>\n\n\n\n<p>Aby po\u0142\u0105czy\u0107 gniazdo z serwerem, wystarczy u\u017cy\u0107:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nsocket.connect(address)\n<\/pre><\/div>\n\n\n<p>gdzie <code>address<\/code> to adres gniazda serwera, z kt\u00f3rym pr\u00f3bujesz si\u0119 po\u0142\u0105czy\u0107 i musi by\u0107 okre\u015blony jako krotka IP:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\n(ip, port)\n<\/pre><\/div>\n\n\n<p>Na przyk\u0142ad:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nsocket.connect((&#039;93.184.216.34&#039;, 80))\n<\/pre><\/div>\n\n\n<p>Chocia\u017c mo\u017cna u\u017cy\u0107 krotki IP, cz\u0119\u015bciej u\u017cywa si\u0119 <code>socket.getaddrinfo<\/code>, aby j\u0105 wygenerowa\u0107.<\/p>\n\n\n\n<p>Zawsze powiniene\u015b zamkn\u0105\u0107 gniazdo po zako\u0144czeniu jego u\u017cywania, wywo\u0142uj\u0105c metod\u0119 <code>close<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wysy\u0142anie i Odbieranie Danych<\/h3>\n\n\n\n<p>Gdy masz ju\u017c po\u0142\u0105czone gniazdo, mo\u017cesz wysy\u0142a\u0107 i odbiera\u0107 dane za pomoc\u0105 r\u00f3\u017cnych metod.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Metody Wysy\u0142ania Danych<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>send(bytes)<\/code>: Zwraca liczb\u0119 faktycznie wys\u0142anych bajt\u00f3w.<\/li>\n\n\n\n<li><code>sendall(bytes)<\/code>: Wysy\u0142a wszystkie dane, nawet je\u015bli wymaga to podzielenia na kilka kawa\u0142k\u00f3w. Nie dzia\u0142a dobrze z gniazdami nieblokuj\u0105cymi, dlatego preferowane jest u\u017cycie <code>write<\/code>.<\/li>\n\n\n\n<li><code>write(buf)<\/code>: Pr\u00f3buje zapisa\u0107 ca\u0142y bufor. Mo\u017ce to nie by\u0107 mo\u017cliwe z gniazdem nieblokuj\u0105cym. Zwraca liczb\u0119 faktycznie wys\u0142anych bajt\u00f3w.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Metody Odbierania Danych<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>recv(len)<\/code>: Zwraca nie wi\u0119cej ni\u017c <code>len<\/code> bajt\u00f3w jako obiekt <code>Bytes<\/code>.<\/li>\n\n\n\n<li><code>recvfrom(len)<\/code>: Zwraca nie wi\u0119cej ni\u017c <code>len<\/code> bajt\u00f3w jako krotk\u0119 <code>(bytes, address)<\/code>, gdzie <code>address<\/code> to adres urz\u0105dzenia wysy\u0142aj\u0105cego dane.<\/li>\n\n\n\n<li><code>read(len)<\/code>: Zwraca nie wi\u0119cej ni\u017c <code>len<\/code> bajt\u00f3w jako obiekt <code>Bytes<\/code>. Je\u015bli <code>len<\/code> nie jest okre\u015blone, czyta tyle danych, ile jest wysy\u0142anych, a\u017c gniazdo zostanie zamkni\u0119te.<\/li>\n\n\n\n<li><code>readinto(buf, len)<\/code>: Odczytuje nie wi\u0119cej ni\u017c <code>len<\/code> bajt\u00f3w do <code>buf<\/code>. Je\u015bli <code>len<\/code> nie jest okre\u015blone, u\u017cywane jest <code>len(buf)<\/code>. Zwraca liczb\u0119 faktycznie odczytanych bajt\u00f3w.<\/li>\n\n\n\n<li><code>readline()<\/code>: Odczytuje lini\u0119, ko\u0144cz\u0105c\u0105 si\u0119 znakiem nowej linii.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Inne Metody<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>sendto(bytes, address)<\/code>: Wysy\u0142a dane do okre\u015blonego adresu \u2013 u\u017cywane gniazdo musi by\u0107 niepo\u0142\u0105czone, aby to dzia\u0142a\u0142o.<\/li>\n\n\n\n<li><code>makefile(mode='rb', buffering=0)<\/code>: Dost\u0119pne dla kompatybilno\u015bci z Pythonem, kt\u00f3ry wymaga konwersji gniazda na plik przed odczytem lub zapisem. W MicroPython mo\u017cna to u\u017cywa\u0107, ale nie ma to \u017cadnego dzia\u0142ania.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Klient HTTP z Gniazdem<\/h4>\n\n\n\n<p>Korzystaj\u0105c z tego, co ju\u017c wiemy o gniazdach, mo\u017cemy \u0142atwo po\u0142\u0105czy\u0107 si\u0119 z serwerem i wysy\u0142a\u0107 oraz odbiera\u0107 dane. Jakie dane faktycznie wysy\u0142amy i odbieramy, zale\u017cy od u\u017cywanego protoko\u0142u. Serwery WWW u\u017cywaj\u0105 HTTP, kt\u00f3ry jest bardzo prostym protoko\u0142em tekstowym. Korzystaj\u0105c z modu\u0142u <code>urequests<\/code>, mogliby\u015bmy ignorowa\u0107 natur\u0119 protoko\u0142u, poniewa\u017c zaimplementowa\u0142 on wi\u0119kszo\u015b\u0107 dla nas. Kiedy u\u017cywamy gniazd, musimy dok\u0142adnie okre\u015bli\u0107, co wys\u0142a\u0107.<\/p>\n\n\n\n<p>Protok\u00f3\u0142 HTTP to zasadniczo zestaw nag\u0142\u00f3wk\u00f3w tekstowych w formacie:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nheadername: headerdata \\r\\n\n<\/pre><\/div>\n\n\n<p>kt\u00f3re informuj\u0105 serwer, co ma zrobi\u0107, oraz zestaw nag\u0142\u00f3wk\u00f3w, kt\u00f3re serwer wysy\u0142a z powrotem, aby poinformowa\u0107, co zrobi\u0142. Mo\u017cesz sprawdzi\u0107 szczeg\u00f3\u0142y nag\u0142\u00f3wk\u00f3w HTTP w dokumentacji \u2013 jest ich sporo.<\/p>\n\n\n\n<p>Najprostsz\u0105 transakcj\u0105 klient-serwer jest wys\u0142anie \u017c\u0105dania GET, aby serwer odes\u0142a\u0142 konkretny plik. Najprostszy nag\u0142\u00f3wek to:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\n&quot;GET \/index.html HTTP\/1.1\\r\\n\\r\\n&quot;\n<\/pre><\/div>\n\n\n<p>co jest \u017c\u0105daniem, aby serwer wys\u0142a\u0142 <code>index.html<\/code>. W wi\u0119kszo\u015bci przypadk\u00f3w potrzebujemy jeszcze jednego nag\u0142\u00f3wka, <code>HOST<\/code>, kt\u00f3ry podaje nazw\u0119 domeny serwera. Dlaczego? Poniewa\u017c HTTP wymaga tego, a wiele stron internetowych jest hostowanych na jednym serwerze pod jednym adresem IP. To, z kt\u00f3rej strony serwer pobiera plik, zale\u017cy od nazwy domeny, kt\u00f3r\u0105 okre\u015blasz w nag\u0142\u00f3wku HOST.<\/p>\n\n\n\n<p>Oznacza to, \u017ce najprostszy zestaw nag\u0142\u00f3wk\u00f3w, jakie mo\u017cemy wys\u0142a\u0107 do serwera, to:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\n&quot;GET \/index.html HTTP\/1.1\\r\\nHOST: example.org\\r\\n\\r\\n&quot;\n<\/pre><\/div>\n\n\n<p>co odpowiada nag\u0142\u00f3wkom:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nGET \/index.html HTTP\/1.1\nHOST: example.org\n<\/pre><\/div>\n\n\n<p>\u017b\u0105danie HTTP zawsze ko\u0144czy si\u0119 pust\u0105 lini\u0105. Je\u015bli jej nie wy\u015blesz, wi\u0119kszo\u015b\u0107 serwer\u00f3w nie odpowie. Dodatkowo nag\u0142\u00f3wek HOST musi mie\u0107 nazw\u0119 domeny bez dodatkowej sk\u0142adni \u2013 bez uko\u015bnik\u00f3w i bez <code>http:<\/code> lub podobnych.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Przyk\u0142ad Klienta HTTP<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nrequest = b&quot;GET \/index.html HTTP\/1.1\\r\\nHost: example.org\\r\\n\\r\\n&quot;\n<\/pre><\/div>\n\n\n<p>Teraz jeste\u015bmy gotowi wys\u0142a\u0107 nasze \u017c\u0105danie do serwera, ale najpierw potrzebujemy jego adresu i musimy po\u0142\u0105czy\u0107 gniazdo:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nai = socket.getaddrinfo(&quot;www.example.com&quot;, 80, socket.AF_INET)\naddr = ai&#x5B;0]&#x5B;-1]\ns = socket.socket(socket.AF_INET)\ns.connect(addr)\n<\/pre><\/div>\n\n\n<p>Teraz mo\u017cemy wys\u0142a\u0107 nag\u0142\u00f3wki, kt\u00f3re stanowi\u0105 \u017c\u0105danie GET:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nrequest = b&quot;GET \/index.html HTTP\/1.1\\r\\nHost: example.org\\r\\n\\r\\n&quot;\ns.send(request)\n<\/pre><\/div>\n\n\n<p>Na koniec mo\u017cemy poczeka\u0107 na odpowied\u017a serwera i wy\u015bwietli\u0107 j\u0105:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nprint(s.recv(512))\n<\/pre><\/div>\n\n\n<p>Zauwa\u017c, \u017ce wszystkie metody s\u0105 blokuj\u0105ce w tym sensie, \u017ce nie zwracaj\u0105 wyniku, dop\u00f3ki operacja nie zostanie zako\u0144czona.<\/p>\n\n\n\n<p>Pe\u0142ny program, z pomini\u0119t\u0105 funkcj\u0105 konfiguracji podan\u0105 wcze\u015bniej, wygl\u0105da nast\u0119puj\u0105co:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nimport network\nimport socket\nfrom machine import Pin, Timer\nfrom time import sleep_ms\n\ndef setup(country, ssid, key):\n    # .  .  .\n    pass\n\nwifi = setup(country, ssid, key)\nprint(&quot;Connected&quot;)\nurl = &quot;http:\/\/192.168.253.72:8080&quot;\nai = socket.getaddrinfo(&quot;www.example.com&quot;, 80, socket.AF_INET)\naddr = ai&#x5B;0]&#x5B;-1]\ns = socket.socket(socket.AF_INET)\ns.connect(addr)\nrequest = b&quot;GET \/index.html HTTP\/1.1\\r\\nHost: example.org\\r\\n\\r\\n&quot;\ns.send(request)\nprint(s.recv(512))\n<\/pre><\/div>\n\n\n<p>Wida\u0107, \u017ce modu\u0142 <code>urequests<\/code> jest znacznie \u0142atwiejszy w u\u017cyciu. Oczywi\u015bcie, korzysta z gniazd do wykonania swojej pracy.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Klient HTTPS oparty na gniazdach SSL w MicroPython<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Wprowadzenie<\/h4>\n\n\n\n<p>Wiele stron internetowych odmawia teraz obs\u0142ugiwania niezaszyfrowanych danych i wymaga u\u017cycia HTTPS. Na szcz\u0119\u015bcie stworzenie klienta HTTPS jest bardzo proste, poniewa\u017c nie musisz tworzy\u0107 certyfikatu cyfrowego. Je\u015bli musisz udowodni\u0107 serwerowi, \u017ce to naprawd\u0119 ty pr\u00f3bujesz si\u0119 po\u0142\u0105czy\u0107, powiniene\u015b zainstalowa\u0107 nowy certyfikat i go u\u017cy\u0107. Procedura ta jest taka sama jak instalowanie nowego certyfikatu serwera, co om\u00f3wimy p\u00f3\u017aniej.<\/p>\n\n\n\n<p>MicroPython ma bardzo minimaln\u0105 implementacj\u0119 modu\u0142u <code>ssl<\/code> z Pythona, ale jest ona wystarczaj\u0105ca do stworzenia klienta lub serwera HTTPS. Posiada tylko jedn\u0105 funkcj\u0119 <code>wrap_socket<\/code>, kt\u00f3ra dodaje szyfrowanie, a w niekt\u00f3rych przypadkach uwierzytelnianie, do istniej\u0105cego gniazda. Obecnie MicroPython dla ESP32 nie obs\u0142uguje uwierzytelniania.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Funkcja wrap_socket<\/h4>\n\n\n\n<p>Funkcja <code>wrap_socket<\/code> wygl\u0105da nast\u0119puj\u0105co:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nssl.wrap_socket(sock, keyfile=None, certfile=None,\n                server_side=False, cert_reqs=ssl.CERT_NONE,\n                ca_certs=None, do_handshake_on_connect=True)\n<\/pre><\/div>\n\n\n<p>Funkcja ta przyjmuje istniej\u0105ce gniazdo okre\u015blone przez <code>sock<\/code> i przekszta\u0142ca je w zaszyfrowane gniazdo SSL. Opr\u00f3cz <code>sock<\/code>, wszystkie jej parametry, w tym <code>keyfile<\/code> i <code>certfile<\/code>, kt\u00f3re okre\u015blaj\u0105 pliki zawieraj\u0105ce certyfikat i\/lub klucz, s\u0105 opcjonalne.<\/p>\n\n\n\n<p>Wszystkie certyfikaty musz\u0105 by\u0107 w formacie PEM (Privacy-Enhanced Mail). Je\u015bli klucz jest przechowywany w certyfikacie, wystarczy u\u017cy\u0107 tylko <code>certfile<\/code>. Je\u015bli klucz jest przechowywany oddzielnie od certyfikatu, potrzebne s\u0105 zar\u00f3wno <code>certfile<\/code>, jak i <code>keyfile<\/code>. Parametr <code>server_side<\/code> ustawia zachowanie odpowiednie dla serwera, gdy jest <code>True<\/code>, a dla klienta, gdy jest <code>False<\/code>. <code>cert_reqs<\/code> okre\u015bla poziom sprawdzania certyfikatu, od <code>CERT_NONE<\/code>, <code>CERT_OPTIONAL<\/code> do <code>CERT_REQUIRED<\/code>. Wa\u017cno\u015b\u0107 certyfikatu jest sprawdzana tylko, gdy wybierzesz <code>CERT_REQUIRED<\/code>, ale obecnie ESP32 nigdy nie sprawdza certyfikatu pod k\u0105tem wa\u017cno\u015bci. <code>ca_certs<\/code> to obiekt typu <code>bytes<\/code> zawieraj\u0105cy certyfikat, kt\u00f3ry ma by\u0107 u\u017cyty do walidacji certyfikatu klienta. <code>server_hostname<\/code> jest u\u017cywany do ustawienia nazwy hosta serwera, aby certyfikat m\u00f3g\u0142 zosta\u0107 sprawdzony i potwierdzony, \u017ce nale\u017cy do danej strony oraz aby serwer m\u00f3g\u0142 przedstawi\u0107 odpowiedni certyfikat, je\u015bli hostuje wiele stron. <code>do_handshake<\/code> powinno by\u0107 u\u017cywane z gniazdami nieblokuj\u0105cymi i gdy jest <code>True<\/code>, op\u00f3\u017ania handshake, natomiast gdy <code>False<\/code>, funkcja nie zwraca, dop\u00f3ki handshake nie zostanie zako\u0144czony.<\/p>\n\n\n\n<p>Zauwa\u017c, \u017ce nie wszystkie parametry pe\u0142nego Pythona <code>wrap_socket<\/code> s\u0105 obs\u0142ugiwane i nie wszystkie poziomy TLS i szyfrowania dzia\u0142aj\u0105. Oznacza to, \u017ce obecnie po\u0142\u0105czenie z niekt\u00f3rymi stronami mo\u017ce by\u0107 trudne lub niemo\u017cliwe. Jednak w wielu przypadkach powinno to po prostu dzia\u0142a\u0107, o ile strona nie u\u017cywa najnowszej implementacji.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Przyk\u0142ad Klienta HTTPS<\/h4>\n\n\n\n<p>Jedyna modyfikacja, jak\u0105 poprzedni klient HTTP potrzebuje, aby dzia\u0142a\u0107 z witryn\u0105 HTTPS, to:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; light: false; title: Kod:; toolbar: true; notranslate\" title=\"Kod:\">\nimport network\nimport socket\nimport ssl\nfrom machine import Pin, Timer\nfrom time import sleep_ms\n\ndef setup(country, ssid, key):\n    # ... konfiguracja WiFi ...\n    pass\n\nwifi = setup(country, ssid, key)\nprint(&quot;Connected&quot;)\n\nai = socket.getaddrinfo(&quot;example.com&quot;, 443, socket.AF_INET)\naddr = ai&#x5B;0]&#x5B;-1]\ns = socket.socket(socket.AF_INET)\ns.connect(addr)\nsslSock = ssl.wrap_socket(s)\n\nrequest = b&quot;GET \/ HTTP\/1.1\\r\\nHost: example.com\\r\\n\\r\\n&quot;\nsslSock.write(request)\nprint(sslSock.read(1024))\n<\/pre><\/div>\n\n\n<p>Zauwa\u017c, \u017ce wystarczy wykona\u0107 domy\u015bln\u0105 funkcj\u0119 <code>wrap_socket<\/code> po nawi\u0105zaniu po\u0142\u0105czenia. Pobrany HTML jest teraz pobierany za pomoc\u0105 HTTPS. <code>sslSock<\/code> zwr\u00f3cony przez funkcj\u0119 <code>wrap_socket<\/code> ma tylko metody strumieniowego odczytu i zapisu.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Podsumowanie<\/h4>\n\n\n\n<p>Je\u015bli chcesz zrobi\u0107 co\u015b wi\u0119cej ni\u017c HTTP lub chcesz zaimplementowa\u0107 serwer HTTP, musisz u\u017cywa\u0107 gniazd.<\/p>\n\n\n\n<p>Gniazda s\u0105 ca\u0142kowicie og\u00f3lne i mo\u017cesz u\u017cywa\u0107 ich do implementacji klienta lub serwera HTTP.<\/p>\n\n\n\n<p>Aby umo\u017cliwi\u0107 r\u00f3\u017cne typy po\u0142\u0105cze\u0144, gniazda mog\u0105 by\u0107 u\u017cywane z r\u00f3\u017cnymi typami adres\u00f3w. W przypadku ESP32 potrzebujemy jednak tylko u\u017cywa\u0107 adres\u00f3w IP.<\/p>\n\n\n\n<p>Klient gniazd musi obs\u0142ugiwa\u0107 szczeg\u00f3\u0142y przesy\u0142anych danych. W szczeg\u00f3lno\u015bci musisz obs\u0142ugiwa\u0107 szczeg\u00f3\u0142y nag\u0142\u00f3wk\u00f3w HTTP.<\/p>\n\n\n\n<p>Implementacja serwera gniazd jest \u0142atwa, ale mo\u017ce by\u0107 trudna do zapewnienia obs\u0142ugi zar\u00f3wno klient\u00f3w, jak i wewn\u0119trznych us\u0142ug.<\/p>\n\n\n\n<p>Najprostszym rozwi\u0105zaniem problemu serwera jest implementacja p\u0119tli pollingowej i do tego musisz u\u017cywa\u0107 gniazd nieblokuj\u0105cych.<\/p>\n\n\n\n<p>Proste gniazda pracuj\u0105 z niezaszyfrowanymi danymi. Je\u015bli chcesz u\u017cywa\u0107 szyfrowania, musisz \u201eopakowa\u0107\u201d gniazdo za pomoc\u0105 modu\u0142u <code>ssl<\/code>.<\/p>\n\n\n\n<p>Klienci HTTPS nie potrzebuj\u0105 certyfikatu do implementacji szyfrowania, ale serwery tak.<\/p>\n\n\n\n<p>Do testowania mo\u017cesz wygenerowa\u0107 w\u0142asne \u201esamopodpisane\u201d certyfikaty, chocia\u017c wi\u0119kszo\u015b\u0107 przegl\u0105darek b\u0119dzie narzeka\u0107, \u017ce nie s\u0105 one bezpieczne.<\/p>\n\n\n\n<p>Kolejka po\u0142\u0105cze\u0144 pozwala obs\u0142u\u017cy\u0107 wi\u0119cej ni\u017c jedno po\u0142\u0105czenie klienta na raz.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Gniazda (ang. sockets) stanowi\u0105 podstaw\u0119 komunikacji przez internet. Ten tutorial pokazuje, jak rozpocz\u0105\u0107 prac\u0119 z gniazdami, aby zaimplementowa\u0107 klient\u00f3w HTTP i HTTPS w j\u0119zyku MicroPython na mikrokontrolerach. Tutorial Wprowadzenie Je\u015bli&#8230;<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[2,80,5,141,65],"tags":[30],"class_list":["post-6203","post","type-post","status-publish","format-standard","hentry","category-arduino","category-esp32","category-esp8266","category-micropython","category-programowanie","tag-tutorial"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/posts\/6203","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/comments?post=6203"}],"version-history":[{"count":28,"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/posts\/6203\/revisions"}],"predecessor-version":[{"id":6249,"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/posts\/6203\/revisions\/6249"}],"wp:attachment":[{"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/media?parent=6203"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/categories?post=6203"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/arduino.net.pl\/index.php\/wp-json\/wp\/v2\/tags?post=6203"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}