简体   繁体   English

如何从“sockaddr_storage”实例中检索 IP 和端口?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM