从 sockaddr 结构中获取 IPV4 地址
Posted
技术标签:
【中文标题】从 sockaddr 结构中获取 IPV4 地址【英文标题】:Getting IPV4 address from a sockaddr structure 【发布时间】:2010-11-19 13:31:47 【问题描述】:如何将 IP 地址提取到字符串中?我找不到告诉我char sa_data[14]
是如何编码的参考资料。
【问题讨论】:
【参考方案1】:只需将整个sockaddr
结构转换为sockaddr_in。然后你可以使用:
char *ip = inet_ntoa(their_addr.sin_addr)
检索标准 ip 表示。
【讨论】:
+1。根据平台,记得先检查家庭。可能没有要提取的 IPV4 地址... @SteveJessop 我们如何进行检查?有没有示例代码或需要寻找的东西?if (their_sockaddr_ptr->sa_family == AF_INET) struct sockaddr_in *their_inaddr_ptr = (struct sockaddr_in *)their_sockaddr_ptr; else /* not an IPv4 address */
,或类似的。
@Emil 如何将整个 sockaddr 结构转换为 sockaddr_in?能举个例子吗? :D
@mister 如果您有问题,请开始提问,这就是 SO 的用途。问题是 SO 上的一等公民。答案是,投吧! sockaddr
只是一个“抽象”地址,没有真正属于这种类型的地址,它只是定义了所有 socketaddr 结构必须具有的公共字段。 struct sockaddr * saddr = ...; if (saddr->sa_family == AF_INET) struct sockaddr_in * saddr_in = (sockaddr_in *)saddr; ...
【参考方案2】:
inet_ntoa()
适用于 IPv4; inet_ntop()
适用于 IPv4 和 IPv6。
给定输入 struct sockaddr *res
,这里有两个 sn-ps 代码(在 macOS 上测试):
使用 inet_ntoa()
#include <arpa/inet.h>
struct sockaddr_in *addr_in = (struct sockaddr_in *)res;
char *s = inet_ntoa(addr_in->sin_addr);
printf("IP address: %s\n", s);
使用 inet_ntop()
#include <arpa/inet.h>
#include <stdlib.h>
// obviously INET6_ADDRSTRLEN is expected to be larger
// than INET_ADDRSTRLEN, but this may be required in case
// if for some unexpected reason IPv6 is not supported, and
// INET6_ADDRSTRLEN is defined as 0
// but this is not very likely and I am aware of no cases of
// this in practice (editor)
char s[INET6_ADDRSTRLEN > INET_ADDRSTRLEN ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN]
= '\0';
switch(res->sa_family)
case AF_INET:
struct sockaddr_in *addr_in = (struct sockaddr_in *)res;
////char s[INET_ADDRSTRLEN] = '\0';
// this is large enough to include terminating null
inet_ntop(AF_INET, &(addr_in->sin_addr), s, INET_ADDRSTRLEN);
break;
case AF_INET6:
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)res;
////char s[INET6_ADDRSTRLEN] = '\0';
// not sure if large enough to include terminating null?
inet_ntop(AF_INET6, &(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
break;
default:
break;
printf("IP address: %s\n", s);
【讨论】:
在哪个标头中? #include 不知道为什么在这里使用 malloc 和 free,静态缓冲区将是更合适的解决方案。【参考方案3】:Emil 的回答是正确的,但我的理解是 inet_ntoa
已被弃用,而您应该使用 inet_ntop
。如果您使用的是 IPv4,请将您的 struct sockaddr
转换为 sockaddr_in
。您的代码将如下所示:
struct addrinfo *res; // populated elsewhere in your code
struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
char ipAddress[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(ipv4->sin_addr), ipAddress, INET_ADDRSTRLEN);
printf("The IP address is: %s\n", ipAddress);
查看this great resource 了解更多说明,包括如何为 IPv6 地址执行此操作。
【讨论】:
【参考方案4】:一旦将sockaddr
转换为sockaddr_in
,就会变成这样:
struct sockaddr_in
u_short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
;
【讨论】:
这比你需要格式化为字符串的要少一些。 我们如何确保铸件安全? @eonil 所有sockaddr
的第一个成员是u_short
类型标签。【参考方案5】:
你可以使用getnameinfo
for Windows和for Linux。
假设你有一个好的(即它的成员有适当的值)sockaddr*
称为pSockaddr
:
char clienthost[NI_MAXHOST]; //The clienthost will hold the IP address.
char clientservice[NI_MAXSERV];
int theErrorCode = getnameinfo(pSockaddr, sizeof(*pSockaddr), clienthost, sizeof(clienthost), clientservice, sizeof(clientservice), NI_NUMERICHOST|NI_NUMERICSERV);
if( theErrorCode != 0 )
//There was an error.
cout << gai_strerror(e1) << endl;
else
//Print the info.
cout << "The ip address is = " << clienthost << endl;
cout << "The clientservice = " << clientservice << endl;
【讨论】:
【参考方案6】:以下程序解析给定域:
$ gcc a.c
$ ./a.out google.com
AF_INET: 216.58.214.238
AF_INET6: 2a00:1450:400d:803::200e
$ ./a.out google.com af_inet
AF_INET: 216.58.214.238
a.c
:
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int
main(int argc, char *argv[])
struct addrinfo hints, *res, *cres;
int r;
char s[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof(hints));
if (argc > 2)
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
r = getaddrinfo(argv[1], NULL, &hints, &res);
if (r)
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(r));
exit(EXIT_FAILURE);
for (cres = res; cres; cres = cres->ai_next)
switch (cres->ai_family)
case AF_INET:
inet_ntop(AF_INET, &((struct sockaddr_in *)cres->ai_addr)->sin_addr, s, INET6_ADDRSTRLEN);
printf("AF_INET: %s\n", s);
break;
case AF_INET6:
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)cres->ai_addr)->sin6_addr, s, INET6_ADDRSTRLEN);
printf("AF_INET6: %s\n", s);
break;
freeaddrinfo(res);
另一个例子可以在here找到。
【讨论】:
【参考方案7】:将sockaddr
类型转换为sockaddr_in
并使用inet_ntoa
检索ipv4
char * ip = inet_ntoa(((struct sockaddr_in *)sockaddr)->sin_addr);
【讨论】:
以上是关于从 sockaddr 结构中获取 IPV4 地址的主要内容,如果未能解决你的问题,请参考以下文章