Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Poprzednia wersja Nowa wersja | Poprzednia wersja | ||
sk2:sockets_netdbs [2018/10/22 16:43] jkonczak [getaddrinfo] |
sk2:sockets_netdbs [2023/10/17 14:03] (aktualna) jkonczak |
||
---|---|---|---|
Linia 10: | Linia 10: | ||
#include <arpa/inet.h> | #include <arpa/inet.h> | ||
#include <netdb.h> | #include <netdb.h> | ||
+ | #include <cstdio> | ||
int main() { | int main() { | ||
| | ||
- | std::thread t1([&]{ | + | std::thread t1([]{ |
sleep(1); | sleep(1); | ||
gethostbyname("spam.org"); | gethostbyname("spam.org"); | ||
}); | }); | ||
| | ||
- | std::thread t2([&]{ | + | std::thread t2([]{ |
- | hostent* ret = gethostbyname("fc.put.poznan.pl"); | + | hostent* ret = gethostbyname("cat.put.poznan.pl"); |
sleep(2); | sleep(2); | ||
printf("%s: %s\n", ret->h_name, inet_ntoa(**(in_addr**)ret->h_addr_list)); | printf("%s: %s\n", ret->h_name, inet_ntoa(**(in_addr**)ret->h_addr_list)); | ||
Linia 36: | Linia 37: | ||
<html><small></html> | <html><small></html> | ||
Kompilator GCC udostępnia wiele rozszerzeń "łatających" braki standardów [[https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html]].\\ | Kompilator GCC udostępnia wiele rozszerzeń "łatających" braki standardów [[https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html]].\\ | ||
- | Między innymi wprowadza funkcje ''gethostbyname_r'' (funkcje ''*_r'' są reentrant, tj. można je bezpiecznie stosować w aplikacjach wielowątkowych [[https://en.wikipedia.org/wiki/Reentrancy_%28computing%29]]) | + | Towarzysząca mu biblioteka [[https://www.gnu.org/software/libc/|glibc]] wprowadza między innymi funkcję ''[[https://www.gnu.org/software/libc/manual/html_node/Host-Names.html#index-gethostbyname_005fr|gethostbyname_r]]'' (funkcje ''*_r'' są reentrant, tj. można je łatwiej stosować w aplikacjach wielowątkowych [[https://en.wikipedia.org/wiki/Reentrancy_%28computing%29]]). ''gethostbyname_r'' może być używana współbieżnie. |
<code cpp> | <code cpp> | ||
hostent he, *resptr; | hostent he, *resptr; | ||
- | int status, retval; | + | int status, retval; |
- | char buffer[4096]; | + | char buffer[4096]; |
- | retval = gethostbyname_r("fc.put.poznan.pl", &he, buffer, sizeof(buffer), &resptr, &status); | + | retval = gethostbyname_r("cat.put.poznan.pl", &he, buffer, sizeof(buffer), &resptr, &status); |
- | if(retval) | + | if(retval) |
- | error(1,0,"gethostbyname_r error: %s", hstrerror(status)); | + | error(1,0,"gethostbyname_r error: %s", hstrerror(status)); |
- | if(!resptr) | + | if(!resptr) |
- | error(1,0,"empty result"); | + | error(1,0,"empty result"); |
- | print(resptr); | + | print(resptr);</code> |
- | </code> | + | |
<html></small></html> | <html></small></html> | ||
===== getaddrinfo ===== | ===== getaddrinfo ===== | ||
- | Standard POSIX wprowadza funkcje ''getaddrinfo'', która pozwala na bezpieczne tłumaczenie nazwy domenowej na adresy IP (zarówno IPv4 i IPv6). Funkcja od razu tworzy gotową strukturę ''sockaddr''. Wynik musi być zwolniony przez programistę funkcją ''freeaddrinfo''. | + | Standard POSIX wprowadza funkcje ''getaddrinfo'', która pozwala na bezpieczne tłumaczenie nazwy domenowej na adresy IP (zarówno IPv4 i IPv6). Funkcja od razu tworzy gotową strukturę ''sockaddr''. Wynik musi być zwolniony przez programistę funkcją ''freeaddrinfo''. Poza ''getaddrinfo'' standard wprowadza też m. inn. funkcję do tłumaczenia ''sockaddr*'' na tekst – ''getnameinfo''. |
<html><small></html> | <html><small></html> | ||
Składnia: <code cpp> | Składnia: <code cpp> | ||
- | int getaddrinfo( // zwraca 0 (ok) lub -1 (błąd) | + | int getaddrinfo( // zwraca 0 (ok) lub niezerowy kod błędu (można go przerobić na tekst używając gai_strerror) |
const char * ip_or_hostname, // nazwa domenowa lub adres IP | const char * ip_or_hostname, // nazwa domenowa lub adres IP | ||
- | const char * port_or_service, // numer portu (np. "80" lub nazwa usługi (np. "http", ustawi port na 80) | + | const char * port_or_service, // numer portu (np. "80") lub nazwa usługi (np. "http", ustawi port na 80) |
const struct addrinfo *hints, // pozwala wybrać typ adresu, wyłączyć używanie DNS, etc. | const struct addrinfo *hints, // pozwala wybrać typ adresu, wyłączyć używanie DNS, etc. | ||
struct addrinfo **res); // pole na wynik (jeśli puste - nic nie znaleziono) | struct addrinfo **res); // pole na wynik (jeśli puste - nic nie znaleziono) | ||
- | </code><html></small></html>Opis struktury ''addrinfo'' znajdziesz na stronie manuala do getaddringo (''man getaddrinfo''). | + | </code> |
+ | Definicja struktury ''addrinfo'':<code cpp> | ||
+ | struct addrinfo { | ||
+ | int ai_flags; | ||
+ | int ai_family; // ai_family, ai_socktype i ai_protocol mają znaczenie identyczne jak | ||
+ | int ai_socktype; // w funkcji socket(). Mogą być ustawione w podpowiedziach na wybraną | ||
+ | int ai_protocol; // wartość lub na 0 (wtedy oznaczają wszystkie pasujące wartości) | ||
+ | socklen_t ai_addrlen; // ai_addr to adres o długości ai_addrlen który może być | ||
+ | struct sockaddr *ai_addr; // użyty w funkcji connect lub bind | ||
+ | char *ai_canonname; | ||
+ | struct addrinfo *ai_next; // struktura addrinfo tworzy jednokierunkową linked listę, ai_next wskazuje na jej następny element | ||
+ | };</code><html></small></html> | ||
+ | |||
+ | Pełen opis funkcji ''getaddrinfo'' i struktury ''addrinfo'' znajdziesz na stronie manuala do getaddrinfo (''man getaddrinfo'') <html><small></html> lub w standardzie POSIX ([[https://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html|[1]]], [[https://pubs.opengroup.org/onlinepubs/9699919799/functions/getnameinfo.html|[2]]], [[https://pubs.opengroup.org/onlinepubs/9699919799/functions/gai_strerror.html|[3]]])<html></small></html>. | ||
+ | \\ | ||
+ | Uwaga: ''getaddrinfo'' w razie sukcesu zwraca ''0'', a w przypadku błędu zwraca jego kod. | ||
Przykłady użycia: | Przykłady użycia: | ||
Linia 68: | Linia 83: | ||
#include <netdb.h> | #include <netdb.h> | ||
#include <cstdio> | #include <cstdio> | ||
- | #include <error.h> | + | #include <error.h> // niestandardowa funkcja ułatwiająca obsługę błędów (dostępna w glibc) |
#include <arpa/inet.h> | #include <arpa/inet.h> | ||
int main(){ | int main(){ | ||
// Ustawienie "podpowiedzi" - sterowanie jakie wyniki chcemy otrzymać: | // Ustawienie "podpowiedzi" - sterowanie jakie wyniki chcemy otrzymać: | ||
- | addrinfo hints {}; | + | addrinfo hints {}; // uwaga: puste 'list initialization' zeruje całą strukturę |
hints.ai_family = AF_INET; // tylko IPv4 (AF_INET) | hints.ai_family = AF_INET; // tylko IPv4 (AF_INET) | ||
- | hints.ai_protocol = IPPROTO_TCP; // protokół TCP | + | hints.ai_protocol = IPPROTO_UDP; // protokół UDP |
| | ||
// Zmienna w której będzie umieszczona lokalizacja wyniku w pamięci | // Zmienna w której będzie umieszczona lokalizacja wyniku w pamięci | ||
addrinfo * resolved; | addrinfo * resolved; | ||
| | ||
+ | // Z sieci bezprzewodowej PP (lub innych używających serwerów nazw z podsieci 150.254.5.0/24) | ||
+ | // proszę zmienić "pool.ntp.org" na "onet.pl" - Dział Obsługi i Eksploatacji z niezrozumiałych | ||
+ | // przyczyn cenzuruje odpowiedzi z DNS | ||
int res = getaddrinfo("pool.ntp.org", "ntp", &hints, &resolved); | int res = getaddrinfo("pool.ntp.org", "ntp", &hints, &resolved); | ||
| | ||
Linia 107: | Linia 125: | ||
| | ||
char ip[40]; // maks. długość IP(v6) jako tekst: 8 bloków po 4 znaki oddzielone ':' | char ip[40]; // maks. długość IP(v6) jako tekst: 8 bloków po 4 znaki oddzielone ':' | ||
+ | // można użyć stałą NI_MAXHOST określającą maksymalną długość nazwy domenowej | ||
for(addrinfo * it = resolved; it; it=it->ai_next){ | for(addrinfo * it = resolved; it; it=it->ai_next){ | ||
// funkcja getnameinfo tłumaczy dowolny sockaddr na tekst | // funkcja getnameinfo tłumaczy dowolny sockaddr na tekst |