Narzędzia użytkownika

Narzędzia witryny


Pasek boczny

sk2:sockets_netdbs

To jest stara wersja strony!


Zmiana adresu domenowego na IP

Tradycyjna funkcja gethostbyname

Najstarsze funkcje do zmiany to gethostbyname i gethostbyaddr. Funkcje są przestarzałe i powszechnie używane. Problemy z ich działaniem obrazuje poniższy kod:

ghbn.cpp
#include <iostream>
#include <netdb.h>
#include <arpa/inet.h>
#include <thread>
#include <atomic>
#include <unistd.h>
 
using namespace std;
 
void print(hostent* ret){
	cout << ret->h_name << endl;
	for(auto it = ret->h_addr_list; *it; ++it){
			cout << "  " << inet_ntoa(*((in_addr*)*it)) << endl;
	}
}
 
int main(int argc, char **argv) {
	atomic<bool> wait1 {true}, wait2 {true};
 
	std::thread 
	t1([&]{
		while(wait1.load());
		gethostbyname("spam.org");
		wait2.store(false);
		sleep(1);
	}),
	t2([&]{
		hostent* ret = gethostbyname("fc.put.poznan.pl");
		wait1.store(false);
		while(wait2.load());
		print(ret);
	});
 
	t1.join();
	t2.join();
	return 0;
}

Rozszerzenia GNU

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)

hostent he, *resptr;
	int status, retval;
	char buffer[4096];
	retval = gethostbyname_r("fc.put.poznan.pl", &he, buffer, sizeof(buffer), &resptr, &status);
	if(retval)
		error(1,0,"gethostbyname_r error: %s", hstrerror(status));
	if(!resptr)
		error(1,0,"empty result");
	print(resptr);

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.

Składnia:

int getaddrinfo(                  // zwraca 0 (ok) lub -1 (błąd) 
    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 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)

Przykład użycia:

#include <netdb.h>
(...)
	// // znajdzie dowolne adresy, w tym IPv6, nie ustawi portu
	// addrinfo * aio;
	// int res = getaddrinfo("fc.put.poznan.pl", 0, 0, &aio);
 
	// znajdzie tylko adresy IPv4, ustawi port 13
	addrinfo * aio, aih {.ai_flags=0, .ai_family=AF_INET, .ai_socktype=SOCK_STREAM}; 
	int res = getaddrinfo("fc.put.poznan.pl", "13", &aih, &aio);
 
	if(res)
		error(1, errno, "getaddrinfo failed");
	if(!aio)
		error(1, 0, "empty result");
	cout << "fc.put.poznan.pl" << endl;
	for(addrinfo * it = aio; ; it=it->ai_next){
		cout << "  " << inet_ntoa(((sockaddr_in*)it->ai_addr)->sin_addr) << endl;
		if(!it->ai_next) break;
	}
	freeaddrinfo(aio);
sk2/sockets_netdbs.1445515369.txt.gz · ostatnio zmienione: 2015/10/22 14:02 przez jkonczak