2009-12-01 17 views
22

Chcę spróbować uzyskać adres IP klienta po wywołaniu accept. To jest to, co mam do tej pory, ale po prostu otrzymuję długą liczbę, która wyraźnie nie jest adresem IP. Co może być nie tak?Jak uzyskać adres IP z sockaddr

int tcp_sock = socket(AF_INET, SOCK_STREAM, 0); 

sockaddr_in client; 
client.sin_family = AF_INET; 
socklen_t c_len = sizeof(client); 

int acc_tcp_sock = accept(tcp_sock, (sockaddr*)&client, &c_len); 
cout << "Connected to: " << client.sin_addr.s_addr << endl; 

Odpowiedz

24

To długa liczba jest adres IP, w postaci liczby całkowitej (adres IP jest tylko liczbą całkowitą, mimo wszystko, jest to po prostu łatwiejsze dla ludzi, aby korzystać kiedy podzielić oktety siebie i umieścić go w kropki notacja).

You can use inet_ntoa skonwertować wartość całkowitą na standardową notację kropkową.

+0

To jest dokładnie to, co musiałem zrobić, dziękuję. – adhanlon

+1

Zauważ, że teraz 'inet_ntoa' jest uważane za przestarzałe. Zamiast tego powinieneś użyć 'inet_ntop', który obsługuje więcej formatów. –

+0

Pamiętaj, że 'inet_ntoa' nie jest bezpieczne dla wątków –

6

to, co otrzymujesz, to nieprzetworzona 32-bitowa reprezentacja adresu IP. dostać znajomy kropka oddziela ciąg, należy użyć funkcji:

char * inet_ntoa(struct in_addr addr); 

że zamieni liczbę całkowitą do statycznego łańcucha.

28

Widziane z http://beej.us/guide/bgnet/examples/client.c:

// get sockaddr, IPv4 or IPv6: 
void *get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

// [...] 

struct addrinfo *p; 
char s[INET6_ADDRSTRLEN]; 
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s); 

Wykorzystuje inet_ntop, który jest bardziej korzystny niż inet_ntoa (thread-safe non), gdyż obsługuje IPv4 i IPv6 (AF_INET i AF_INET6) i powinien być bezpieczny wątku myślę.

3

Poniżej jest pobierana z przykładu https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/epoll-example.c

   struct sockaddr in_addr; 
       socklen_t in_len; 
       int infd; 
       char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 

       in_len = sizeof in_addr; 
       infd = accept (sfd, &in_addr, &in_len); 
       if (infd == -1) 
       { 
        if ((errno == EAGAIN) || 
         (errno == EWOULDBLOCK)) 
        { 
         /* We have processed all incoming 
         connections. */ 
         break; 
        } 
        else 
        { 
         perror ("accept"); 
         break; 
        } 
       } 

       s = getnameinfo (&in_addr, in_len, 
       hbuf, sizeof hbuf, 
       sbuf, sizeof sbuf, 
       NI_NUMERICHOST | NI_NUMERICSERV); 
       if (s == 0){ 
        printf("Accepted connection on descriptor %d " 
         "(host=%s, port=%s)\n", infd, hbuf, sbuf); 
       } 
0

Chociaż są to dobre odpowiedzi, że złamałem skompilować z -pedantic -std=c99 -Werror.

Z Man7 gniazdo

umożliwienia wprowadzenia typ adresu gniazda mają być przekazane do interfejsu API w gniazdach, typ struct sockaddr jest zdefiniowana. Celem tego typu jest umożliwienie odlewania specyficznych dla domeny adresów gniazd o nazwach typu "ogólnego", aby uniknąć ostrzeżeń kompilatora na temat niedopasowania wywołań do API gniazd w typie .

Aby uzyskać wszystkie istotne dane na tej stronie, z glibc-2,17 (RHEL7) widzę

/* Structure describing a generic socket address. */ 
struct sockaddr 
    { 
    __SOCKADDR_COMMON (sa_); /* Common data: address family and length. */ 
    char sa_data[14];  /* Address data. */ 
    }; 

gdzie SOCKADDR_COMMON jest uint16_t. Łączny rozmiar to 16B.

IP (Internet Protocol) domeny specyficzne, z człowieka 7 ip:

struct sockaddr_in { 
    sa_family_t sin_family; /* address family: AF_INET */ 
    in_port_t  sin_port; /* port in network byte order */ 
    struct in_addr sin_addr; /* internet address */ 
}; 

/* Internet address. */ 
struct in_addr { 
    uint32_t  s_addr;  /* address in network byte order */ 
}; 

Najpierw spróbuj

inet_ntoa(((struct sockaddr_in) peer_addr).sin_addr) 

Problem

error: conversion to non-scalar type requested 

drugie spróbować

inet_ntoa(((struct sockaddr_in *) &peer_addr)->sin_addr))); 

Problem

error: dereferencing type-punned pointer might break strict-aliasing rules [-Werror=strict-aliasing] 

Thrid try: inet_pton, bardziej nowoczesny anyways, wątek bezpieczny, bierze void *

char peer_addr_str[ INET_ADDRSTRLEN ]; 
inet_ntop(AF_INET, &peer_addr, peer_addr_str, INET_ADDRSTRLEN); 

ok, działa. Odczytywalny ludzki ciąg znaków dziesiętnych i kropek jest w peer_addr_str.

0

Możesz użyć funkcji getnameinfo dostępnej dla systemów Linux i Windows. Od Linux stron podręcznika https://linux.die.net/man/3/getnameinfo:

getnameinfo - adres do nazwy tłumaczenie w protokole niezależny sposób

przykładu dla C/C++ (Linux):

#include <sys/socket.h> 
#include <netdb.h> 
#include <stdio.h> 

char host[NI_MAXHOST]; // to store resulting string for ip 
if (getnameinfo((sockaddr*)&client, c_len, 
        host, NI_MAXHOST, // to try to get domain name don't put NI_NUMERICHOST flag 
        NULL, 0,   // use char serv[NI_MAXSERV] if you need port number 
        NI_NUMERICHOST // | NI_NUMERICSERV 
       ) != 0) { 
    //handle errors 
} else { 
    printf("Connected to: %s\n", host);  
} 

To jest czysty odpowiedzi na @enthusiasticgeek. Jego odpowiedź ma działający przykład z akceptacją połączenia.

Powiązane problemy