[英]How to retrieve IP and port from a `sockaddr_storage` instance?
How can I retrieve IP and port from a sockaddr_storage
instance with getnameinfo()
( ref )?如何使用
getnameinfo()
( ref ) 从sockaddr_storage
实例检索 IP 和端口?
When I used inet_ntop
, it worked like normal, but when I replaced it with the getnameinfo
function, Windows returned an error:当我使用
inet_ntop
时,它正常工作,但是当我用getnameinfo
function 替换它时,Windows 返回错误:
Code 10047: An address incompatible with the requested protocol was used.
代码 10047:使用了与请求的协议不兼容的地址。
#ifdef USE_IPV6
int fd = socket(AF_INET6, SOCK_DGRAM, 0);
#else
int fd = socket(AF_INET, SOCK_DGRAM, 0);
#endif
sockaddr_storage address;
int length = sizeof address;
char buffer[1];
recvfrom(fd, buffer, sizeof buffer, 0, (struct sockaddr *) &address, &length);
// Error
char ip[NI_MAXHOST];
char port[NI_MAXSERV];
int rc = getnameinfo((struct sockaddr *) &address, length, ip, sizeof ip, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV);
if (rc) WSAGetLastError(); // Error Code = 10047
// Works
#ifdef USE_IPV6
struct sockaddr_in6 *sa = (struct sockaddr_in6 *) &address;
inet_ntop(AF_INET6, &sa->sin6_addr, ip, INET6_ADDRSTRLEN);
uint16_t port_ = ntohs(sa->sin6_port);
#else
struct sockaddr_in *sa = (struct sockaddr_in *) &address;
inet_ntop(AF_INET, &sa->sin_addr, ip, INET_ADDRSTRLEN);
uint16_t port_ = ntohs(sa->sin_port);
#endif
I took a look at your issue and was able to reproduce the error you were having.我查看了您的问题,并能够重现您遇到的错误。
Reproducible example:可重现的例子:
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
int main(int, char **) {
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
WSAStartup(wVersionRequested, &wsaData);
#ifdef USE_IPV6
int fd = socket(AF_INET6, SOCK_DGRAM, 0);
#else
SOCKET fd = socket(AF_INET, SOCK_DGRAM, 0);
#endif
sockaddr_storage address;
int length = sizeof(sockaddr_storage);
char buffer[1];
recvfrom(fd, buffer, sizeof buffer, 0, (struct sockaddr*)&address, &length);
// Error
char ip[NI_MAXHOST];
char port[NI_MAXSERV];
int rc = getnameinfo((struct sockaddr*)&address,
length,
ip,
sizeof(ip),
port,
sizeof(port),
NI_NUMERICHOST | NI_NUMERICSERV);
if (rc)
WSAGetLastError(); // Error Code = 10047
std::cout << "IP: " << ip << std::endl;
std::cout << "Port: " << port << std::endl;
// Works
#ifdef USE_IPV6
struct sockaddr_in6* sa = (struct sockaddr_in6*)&address;
inet_ntop(AF_INET6, &sa->sin6_addr, ip, INET6_ADDRSTRLEN);
uint16_t port_ = ntohs(sa->sin6_port);
#else
struct sockaddr_in* sa = (struct sockaddr_in*)&address;
inet_ntop(AF_INET, &sa->sin_addr, ip, INET_ADDRSTRLEN);
uint16_t port_ = ntohs(sa->sin_port);
#endif
}
The issue lies in the fact that you aren't setting the ss_family
field of the sockaddr_storage
structure.问题在于您没有设置
ss_family
sockaddr_storage
结构的字段。
To fix this, you need to specify the ss_family
value in the sockaddr_storage
as follows:要解决此问题,您需要在
sockaddr_storage
中指定ss_family
值,如下所示:
sockaddr_storage address;
address.ss_family = AF_INET;
Once you do this, you should not see error 10047 anymore and you should be able to print the contents of the ip and port buffers and see the respective information.执行此操作后,您将不会再看到错误 10047,并且您应该能够打印 ip 和端口缓冲区的内容并查看相应的信息。
References:参考:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.