Az internethez való csatlakozáshoz az ESP32 a szokásos internet socket megoldást alkalmazza, az LWIP alkalmazásával. Ha csatlakozni akarunk WiFi-n keresztül a nethez, először létre kell hozni a kapcsolatunkat egy WiFi állomással. Mivel a WiFi-ről a gyártó, azaz az Espressif nem nagyon hozott nyilvánosságra részletes információt, használjuk a szokásos módszert:
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Utána, hogy csatlakozni tudjunk egy adott internetes oldalhoz, létre kell hoznunk egy socket-ot, egy internetes csatlakozási pontot, aminek én a socket_descriptor azonosítót adtam.
int socket_descriptor = socket(AF_INET , SOCK_STREAM , 0);
Létrejön egy socket, ami tulajdonképpen egy file. Visszatérési értékként kapunk egy 64-nél kisebb egész számot, egy socket descriptort, file descriptort, ami egy index. Megmutatja, hogy a fájlok jellemzőit leíró táblában hol található az adott socketra vonatkozó információ.
A socket 3 paramétere rendre:
Ahhoz, hogy csatlakozni tudjunk, meg kell adni a cél adatait egy sockaddr_in típusú struktúrában, aminek a példában a connect_to_remote_server_addr azonosítót adtam.
struct sockaddr_in connect_to_remote_server_addr;
Megadjuk az elemeit, azaz a protocol típusát (AF_INET=IPv4):
connect_to_remote_server_addr.sin_family = AF_INET;
A cél IP címét:
connect_to_remote_server_addr.sin_addr.s_addr = inet_addr("216.58.208.110");
//ip address of google.com as a sample
A portot:
connect_to_remote_server_addr.sin_port = htons( 80 );
//htons: translate an unsigned short integer into network byte order
Itt mintaként a Google-nak e sorok írásakori IP címe szerepel. Ezzel már kapcsolódhatunk a távoli szerverhez. Mi egy IPv4-hez passzoló, sockaddr_in struktúrában adtuk meg az adatokat, viszont a connect általánosabb, sockaddr típusú, de ugyanolyan hosszú struktúrát vár, ezért castolni kell.
connect(
socket_descriptor ,
(struct sockaddr * ) &connect_to_remote_server_addr ,
sizeof(connect_to_remote_server_addr)
)
A kapcsolat felépítése után elküldjük a lekérést, tipikusan a "GET / HTTP/1.1\r\n\r\n" szöveget:
char * myMessage2server;
myMessage2server = "GET / HTTP/1.1\r\n\r\n";
send(
socket_descriptor ,
myMessage2server ,
strlen(myMessage2server) ,
0
)
Mivel a létrehozott socket is egy fájl, használhatjuk a send helyett a write utasítást is (Google : "write to a file descriptor")
write(
socket_descriptor ,
myMessage2server ,
strlen(myMessage2server)
)
A send/write, illetve a recv/read közötti különbség, hogy előbbi esetén van egy negyedik "flag" paraméter, ami általában 0, de pl. peek esetén MSG_PEEK, azaz 1.
A lekérés elküldése után várjuk a választ:
int received_data_size_max = 5000 ;
char received_data_from_server [ received_data_size_max ]
recv(
socket_descriptor,
received_data_from_server,
received_data_size_max ,
0
)
Ebben a példában a választ kiíratjuk kiíratjuk:
printf(received_data_from_server)
Válaszként egy így kezdődő üzenetet kapunk:
HTTP/1.1 200 OK
A végén a kapcsolatot be kell zárni:
close(socket_descriptor)
Mivel a socket is file, használhatók a fájlműveletek is. Például a következő megoldás a beérkező első 5 sort kiírja:
FILE* filePointer = fdopen(socket_descriptor, "r+");
if (filePointer == nullptr){ printf("\n\nnullpointer\n\n\n");};
fprintf (filePointer, myMessage2server) ;
char inputChars[200];
for (int i = 0;i<5;i++){
fgets(inputChars, 199, filePointer);
printf("%s", inputChars);
} ;
Végezetül megjegyzem, hogy az egyes utasítások helyett az LWIP utasításai fordítódnak be, például így:
#define lwip_socket socket
#define lwip_write write
Tömörebb változat:
/* tutorial receive data from remote server */ #include <WiFi.h> #include <lwip/sockets.h> const char* ssid = "**********"; const char* password = "**********"; void setup() { Serial.begin(115200); delay(2000); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } printf("\nconnected to WiFi \n"); int socket_descriptor = socket(AF_INET , SOCK_STREAM , 0); if (socket_descriptor == -1) { printf("Could not create socket"); } struct sockaddr_in connect_to_remote_server_addr; connect_to_remote_server_addr.sin_family = AF_INET; connect_to_remote_server_addr.sin_addr.s_addr = inet_addr("216.58.208.110"); // Google connect_to_remote_server_addr.sin_port = htons( 80 ); if (connect( socket_descriptor , (struct sockaddr *)&connect_to_remote_server_addr , sizeof(connect_to_remote_server_addr) ) < 0 ) { // if < 0 printf("Connect error to remote server\n"); } else { printf("Connected to remote server\n\n"); } ; // end if FILE* filePointer = fdopen(socket_descriptor, "r+"); if (filePointer == nullptr){ printf("\n\nnullpointer\n\n\n");}; fprintf (filePointer, "GET / HTTP/1.1\r\n\r\n") ; char inputChars[200]; for (int i = 0;i<5;i++){ fgets(inputChars, 199, filePointer); printf("%s", inputChars); } ; close(socket_descriptor); } ; // end setup void loop() { }
Kommentekkel:
/* tutorial receive data from remote server */ #include <WiFi.h> #include <lwip/sockets.h> const char* ssid = "*************"; const char* password = "**********"; void setup() { Serial.begin(115200); delay(2000); Serial.println("setup started"); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } printf("\nconnected to WiFi \n"); int socket_descriptor = socket(AF_INET , SOCK_STREAM , 0); // socket descriptor = file descriptor printf("socket_descriptor = %d \n",socket_descriptor); // AF_INET : address family IPv4 // SOCK_STREAM : TCP socket //#define AF_INET 2 //#define AF_INET6 10 //#define SOCK_STREAM 1 //TCP socket //#define SOCK_DGRAM 2 //UDP socket //#define SOCK_RAW 3 //used to generate/receive packets of a type //that the kernel doesn't explicitly support. if (socket_descriptor == -1) { printf("Could not create socket"); } struct sockaddr_in connect_to_remote_server_addr; //members are in network byte order //struct sockaddr_in { //LWIP_IPV4, sockaddr_in for IPv4 // u8_t sin_len; // sa_family_t sin_family; // in_port_t sin_port; // struct in_addr sin_addr; // #define SIN_ZERO_LEN 8 // char sin_zero[SIN_ZERO_LEN]; //}; connect_to_remote_server_addr.sin_family = AF_INET; connect_to_remote_server_addr.sin_addr.s_addr = inet_addr("216.58.208.110"); //ip address of google.com as a sample connect_to_remote_server_addr.sin_port = htons( 80 ); //htons: translate an unsigned short integer into network byte order //Connect to remote server // struct sockaddr { // = protocol independent ("polymorphism") // u8_t sa_len; // sa_family_t sa_family; // char sa_data[14]; //}; if (connect( socket_descriptor , (struct sockaddr *)&connect_to_remote_server_addr , sizeof(connect_to_remote_server_addr) ) < 0 ) { // if < 0 printf("Connect error to remote server\n"); } else { printf("Connected to remote server\n"); } ; // end if ; //Send some data char *myMessage2server; myMessage2server = "GET / HTTP/1.1\r\n\r\n"; if( send(socket_descriptor , myMessage2server , strlen(myMessage2server) , 0) < 0) // or write(socket_descriptor , myMessage2server , strlen(myMessage2server)) { printf("Send failed to remote server\n"); } else { printf("Data send to remote server\n"); } ; //Receive data on socket //Receive a reply from the server int received_data_size_max = 5000 ; char received_data_from_server[received_data_size_max]; if( recv( socket_descriptor, received_data_from_server, received_data_size_max , 0 // or MSG_PEEK: #define MSG_PEEK 0x01 Peeks at an incoming message ) < 0) // or read(socket_descriptor,received_data_from_server,received_data_size_max) { // if < 0 printf("receive from server failed\n"); }else { printf("Reply received from remote server:\n"); printf(received_data_from_server); } ; // end if //Close socket: close(socket_descriptor); } ; // end setup void loop() { // put your main code here, to run repeatedly: }