English 中文(简体)
How to get IP address from sockaddr
原标题:

I want to try and get the ip address of a client after calling accept. This is what I have so far, but I just end up getting some long number that is clearly not an ip address. What could be wrong?

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;
最佳回答

That long number is the IP address, in integer form (an IP address is just an integer, after all; it s just easier for people to use when we split the octets apart and put it into dot notation).

You can use inet_ntoa to convert the integer value to standard dot notation.

问题回答

Seen from 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);

It uses inet_ntop, which is preferred over inet_ntoa (non thread-safe) as it handles IPv4 and IPv6 (AF_INET and AF_INET6) and should be thread-safe I think.

what your are getting is the raw 32 bit integer representation of the IP address. to get the familiar dot separated string, use the function:

 char * inet_ntoa(struct in_addr addr);

that will convert the integer to a static string.

The following is taken from the example 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)
", infd, hbuf, sbuf);
                 }

While these are good answers, they broke my compile with -pedantic -std=c99 -Werror.

From man 7 socket

To allow any type of socket address to be passed to interfaces in the sockets API, the type struct sockaddr is defined. The purpose of this type is purely to allow casting of domain-specific socket address types to a "generic" type, so as to avoid compiler warnings about type mismatches in calls to the sockets API.

To get all the relevant data in this page, from glibc-2.17 (RHEL7) I see

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

where SOCKADDR_COMMON is a uint16_t. So total size is 16B.

IP (internet protocol) Domain specific, from man 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 */
};

First try

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

Problem

error: conversion to non-scalar type requested

Second try

 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, more modern anyways, thread safe, takes void*

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

ok, works. Human readable decimal-and-dots string is in peer_addr_str.

You can use getnameinfo function that is available for Linux and Windows. From Linux man pages https://linux.die.net/man/3/getnameinfo:

getnameinfo - address-to-name translation in protocol-independent manner

Example for 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
", host);     
}

This is clean up of @enthusiasticgeek answer. His answer has a working example with accept call.





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签