Linux 如何使用套接字地址获取自己的IP地址?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15914790/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get its own IP address with a socket address?
提问by Julien Fouilhé
I want to get the IP address of the computer my program is launched on, to be able then to send it to a client, but I always get 0.0.0.1 instead of the real IP address (like 127.0.0.1 for instance).
我想获取启动我的程序的计算机的 IP 地址,以便能够将其发送给客户端,但我总是得到 0.0.0.1 而不是真实的 IP 地址(例如 127.0.0.1)。
I'm currently able to get the port, but not the IP address.
我目前能够获取端口,但不能获取 IP 地址。
How can I get it?
我怎么才能得到它?
The best solution would be to be able to get it with a sockaddr_in
. Here's what I'm currently doing:
最好的解决方案是能够使用sockaddr_in
. 这是我目前正在做的事情:
int open_connection(char* ip, int* port)
{
int sock;
struct sockaddr_in sin;
socklen_t len;
int i;
i = 0;
len = sizeof(sin);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return (-1);
bzero(&sin, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0)
perror("Error on bind");
if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0)
perror("Error on getsockname");
strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0
*port = sin.sin_port;
return (sock);
}
EDIT:I understand I was going on the wrong way with my way of thinking. So my question is: What's the best way to get your own IP address?
编辑:我知道我的思维方式是错误的。所以我的问题是:获得自己的 IP 地址的最佳方法是什么?
采纳答案by Remy Lebeau
When you bind()
a socket to 0.0.0.0, that is the only IP the socket has available when calling getsockname()
. It means the socket is bound to all local interfaces. In order to get a specific IP from a socket, it has to be bound to a specific IP.
当您bind()
将套接字设置为 0.0.0.0 时,这是该套接字在调用getsockname()
. 这意味着套接字绑定到所有本地接口。为了从套接字获取特定 IP,它必须绑定到特定 IP。
Using the socket API to get the machine's local IP(s) is the wrong approach anyway. A common mistake is to use gethostname()
with gethostbyname()
or getaddrinfo()
to get the local IP list. Usually that works, but it has some hidden gotchas that can cause false information, but people tend to ignore that fact, or don't even know about it in the first place (I didn't know about it for years, but then I learned better).
无论如何,使用套接字 API 获取机器的本地 IP 是错误的方法。一个常见的错误是使用gethostname()
withgethostbyname()
或getaddrinfo()
获取本地 IP 列表。通常这是有效的,但它有一些隐藏的问题,可能会导致错误信息,但人们往往会忽略这个事实,或者甚至一开始就不知道(我多年来都不知道,但后来我学得更好)。
Instead, you really should use platform-specific APIs for enumerating the local networking interfaces. That will provide more reliable information. Windows has GetAdaptersInfo()
and GetAdaptersAddresses()
. Other platforms have getifaddrs()
. Those will tell you what local IPs are available. You can then bind()
a socket to 0.0.0.0 in order to accept clients on any of those IPs, or bind()
to a specific IP to accept clients only on that IP.
相反,您确实应该使用特定于平台的 API 来枚举本地网络接口。这将提供更可靠的信息。Windows 具有GetAdaptersInfo()
和GetAdaptersAddresses()
. 其他平台有getifaddrs()
。这些将告诉您哪些本地 IP 可用。然后,您可以将bind()
套接字连接到 0.0.0.0 以接受任何这些 IP 上的客户端,或者连接bind()
到特定 IP 以仅接受该 IP 上的客户端。
回答by Havenard
The sockets API allows you to enumerate the IP addresses assigned to your network interfaces, but it will not tell you what you "real IP" is if you are connecting to the Internet from behind a router.
套接字 API 允许您枚举分配给网络接口的 IP 地址,但如果您从路由器后面连接到 Internet,它不会告诉您“真实 IP”是什么。
The only way to know it is by asking someone outside. Thats how servers like FileZilla FTP Server do that. They instruct you to configure the URL to a "ip.php" script like this onein the server's settings so it can ask the Internet whats its public IP address, to use in Passive Mode.
要知道它的唯一方法是询问外面的人。FileZilla FTP Server 这样的服务器就是这样做的。他们指导您配置URL为“ip.php”脚本像这样一个在服务器的设置,使其可以要求互联网什么的公网IP地址,在被动模式下使用。
You can also consider using STUN, a protocol widely used in VoIP to discover public IP.
您还可以考虑使用STUN,一种广泛用于 VoIP 的协议来发现公共 IP。
回答by Grandswiss
You could call ioctl(sock, SIOCGIFADDR, adr)
你可以调用 ioctl(sock, SIOCGIFADDR, adr)
see netdevice(7)
见网络设备(7)
回答by Yuan Fu
Following @Remy Lebeau
's answer I wrote a function that return current machine's address. I have only tested this on macOS High Sierra.
以下@Remy Lebeau
的回答我写了一个返回当前机器地址的函数。我只在 macOS High Sierra 上测试过。
interfaec
can be anything among lo0
, en0
, etc.
interfaec
可以跻身什么lo0
,en0
等等。
ipVersion
can be AF_INET
or AF_INET6
.
ipVersion
可以AF_INET
或AF_INET6
。
long int getInternalAddress(char* interface, sa_family_t ipVersion)
{
struct ifaddrs *ifaddrHead, *ifaddr;
/* int_8 */
sa_family_t family;
int n;
char *interfaceName;
if (getifaddrs(&ifaddrHead) != 0)
{
fprintf(stderr, "ifaddrs error");
}
/* iterate through address list */
for (ifaddr = ifaddrHead, n = 0; ifaddr != NULL; ifaddr = ifaddr->ifa_next, n++)
{
family = ifaddr->ifa_addr->sa_family;
interfaceName = ifaddr->ifa_name;
if (!family || family != ipVersion || strcmp(interfaceName, interface)) continue;
struct sockaddr *addr = ifaddr->ifa_addr;
struct sockaddr_in* addr_in = (struct sockaddr_in*) addr;
long int address = addr_in->sin_addr.s_addr;
freeifaddrs(ifaddrHead);
return address;
}
freeifaddrs(ifaddrHead);
return 0;
}
To use it,
要使用它,
int main()
{
long int address = getInternalAddress((char*) &"en0", AF_INET);
printf("%li\n", address);
return 0;
}
I'm still a beginner in C, if there is anything wrong please tell me.
我还是 C 的初学者,如果有什么不对的请告诉我。