Understanding INADDR_ANY for socket programming

I am trying to program some sockets and so, on the server side, I use htonl(INADDR_ANY). To the extent I understood, it seems to me that this function generates a random IP (am I correct ?). In fact, I want to bind my socket with my localhost. But if I run this

printf("%d",htonl(INADDR_ANY));

I get 0 as a return value. Could someone bring some explanation ?

233676 次浏览

INADDR_ANY is used when you don't need to bind a socket to a specific IP. When you use this value as the address when calling bind(), the socket accepts connections to all the IPs of the machine.

  1. bind() of INADDR_ANY does NOT "generate a random IP". It binds the socket to all available interfaces.

  2. For a server, you typically want to bind to all interfaces - not just "localhost".

  3. If you wish to bind your socket to localhost only, the syntax would be my_sockaddress.sin_addr.s_addr = inet_addr("127.0.0.1");, then call bind(my_socket, (SOCKADDR *) &my_sockaddr, ...).

  4. As it happens, INADDR_ANY is a constant that happens to equal "zero":

    http://www.castaglia.org/proftpd/doc/devel-guide/src/include/inet.h.html

    # define INADDR_ANY ((unsigned long int) 0x00000000)
    ...
    # define INADDR_NONE    0xffffffff
    ...
    # define INPORT_ANY 0
    ...
    
  5. If you're not already familiar with it, I urge you to check out Beej's Guide to Sockets Programming:

    http://beej.us/guide/bgnet/

Since people are still reading this, an additional note:

man (7) ip:

When a process wants to receive new incoming packets or connections, it should bind a socket to a local interface address using bind(2).

In this case, only one IP socket may be bound to any given local (address, port) pair. When INADDR_ANY is specified in the bind call, the socket will be bound to all local interfaces.

When listen(2) is called on an unbound socket, the socket is automatically bound to a random free port with the local address set to INADDR_ANY.

When connect(2) is called on an unbound socket, the socket is automatically bound to a random free port or to a usable shared port with the local address set to INADDR_ANY...

There are several special addresses: INADDR_LOOPBACK (127.0.0.1) always refers to the local host via the loopback device; INADDR_ANY (0.0.0.0) means any address for binding...

Also:

bind() — Bind a name to a socket:

If the (sin_addr.s_addr) field is set to the constant INADDR_ANY, as defined in netinet/in.h, the caller is requesting that the socket be bound to all network interfaces on the host. Subsequently, UDP packets and TCP connections from all interfaces (which match the bound name) are routed to the application. This becomes important when a server offers a service to multiple networks. By leaving the address unspecified, the server can accept all UDP packets and TCP connection requests made for its port, regardless of the network interface on which the requests arrived.

To bind socket with localhost, before you invoke the bind function, sin_addr.s_addr field of the sockaddr_in structure should be set properly. The proper value can be obtained either by

my_sockaddress.sin_addr.s_addr = inet_addr("127.0.0.1")

or by

my_sockaddress.sin_addr.s_addr=htonl(INADDR_LOOPBACK);

INADDR_ANY is a constant, that contain 0 in value . this will used only when you want connect from all active ports you don't care about ip-add . so if you want connect any particular ip you should mention like as my_sockaddress.sin_addr.s_addr = inet_addr("192.168.78.2")

INADDR_ANY instructs listening socket to bind to all available interfaces. It's the same as trying to bind to inet_addr("0.0.0.0"). For completeness I'll also mention that there is also IN6ADDR_ANY_INIT for IPv6 and it's the same as trying to bind to :: address for IPv6 socket.

#include <netinet/in.h>


struct in6_addr addr = IN6ADDR_ANY_INIT;

Also, note that when you bind IPv6 socket to IN6ADDR_ANY_INIT your socket will bind to all IPv6 interfaces, and should be able to accept connections from IPv4 clients as well (though IPv6-mapped addresses).

When you have a server, you create a socket and then you bind it to an IP and port, which gives the socket a unique way to be identified based on a unique socket type, address family, IP and port. You then listen() to set the socket to server mode, and then you do accept(), which waits on a connection which will have inbound packets with target IP/port that cause the packets to be queued on that socket. You don't need to bind it to an IP however, it can accept connections on all interfaces.

When you have a client, you create a socket, and then you connect() the socket to a remote IP and port, which will also bind 0.0.0.0 and a random unused ephemeral port to the socket if it hasn't been already bound to an IP and port using bind(INADDR_ANY, 0). connect() returns when it connects, and uses the IP and port as the source address in the outbound packets, where 0.0.0.0 is always substituted with an IP based on src hint in the routing table or the IP of the selected interface (if it has multiple IPs then first IP with same or bigger scope is selected), and then you use sendall to send application data.

INADDR_ANY is faster than programmatically acquiring the current internal IP of the interface, which could change at any moment, and packets will no longer be received on the port, but they'd still be received on 0.0.0.0 because it is any address.

Note that a socket can be bound to 0.0.0.0, but not port 0, because its a wildcard that makes it give the socket a random ephemeral port, so when you use bind(INADDR_ANY, 0) it binds to 0.0.0.0 and a random ephemeral port.

#include <arpa/inet.h>
.
.
tcpsock.sin_addr.s_addr = inet_addr("192.168.1.2")

worked for me