如何解决如何从`sockaddr_storage`实例中检索IP和端口?
如何使用sockaddr_storage
(ref)从getnameinfo()
实例检索IP和端口?
当我使用inet_ntop
时,它的工作正常,但是当我将其替换为getnameinfo
函数时,Windows返回了一个错误:
代码10047:使用了与请求的协议不兼容的地址。
#ifdef USE_IPV6
int fd = socket(AF_INET6,SOCK_DGRAM,0);
#else
int fd = socket(AF_INET,0);
#endif
sockaddr_storage address;
int length = sizeof address;
char buffer[1];
recvfrom(fd,buffer,sizeof buffer,(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,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,INET_ADDRSTRLEN);
uint16_t port_ = ntohs(sa->sin_port);
#endif
解决方法
我查看了您的问题,并能够重现您遇到的错误。
可复制的示例:
#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,0);
#endif
sockaddr_storage address;
int length = sizeof(sockaddr_storage);
char buffer[1];
recvfrom(fd,buffer,sizeof buffer,(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,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,INET_ADDRSTRLEN);
uint16_t port_ = ntohs(sa->sin_port);
#endif
}
问题在于您没有设置ss_family
结构的sockaddr_storage
字段。
要解决此问题,您需要在ss_family
中指定sockaddr_storage
值,如下所示:
sockaddr_storage address;
address.ss_family = AF_INET;
执行完此操作后,您将不再看到错误10047,并且应该能够打印ip和port缓冲区的内容并查看相应的信息。
参考: