Портативное компактное представление IP-адреса - PullRequest
0 голосов
/ 06 марта 2012

У меня есть программа на C ++, использующая API сокетов Berkley в Linux.У меня есть один конец соединения, отправляющий два IP-адреса клиенту.Я могу представить их, используя inet_ntop() и inet_pton(), но при этом длина сообщения составит 2*INET6_ADDRSTRLEN, что составляет 92 байтов.Это кажется немного для двух IP-адресов.Существует ли портативное компактное двоичное представление IP-адресов (оно должно работать как с IPv4, так и с IPv6).

Ответы [ 2 ]

0 голосов
/ 09 марта 2012

Если у вас валяется адринфо, отправьте .ai_addr и .ai_addrlen.

Попробуйте эти две программы:

send_sockaddr.cc:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <cstdio>
#include <cerrno>
#include <cstdlib>

int main (int ac, char **av) {

  if(ac != 3) {
    fprintf(stderr, "Usage: %s hostname portnumber\n", *av);
    return 1;
  }

  struct addrinfo *res0;
  struct addrinfo hints = { AI_CANONNAME, 0, SOCK_DGRAM };
  int rc = getaddrinfo(av[1], av[2], &hints, &res0);
  if(rc) {
    fprintf(stderr, "%s/%s: %s\n", av[1], av[2], gai_strerror(rc));
    return 1;
  }

  char *name = res0->ai_canonname;
  for(struct addrinfo *res = res0; res; res=res->ai_next) {
    fprintf(stderr, "%s: %04X/%04X/%04X ", name, res->ai_family, res->ai_socktype, res->ai_protocol);
    int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if(fd < 0) {
      perror("socket");
      continue;
    }

    rc = connect(fd, res->ai_addr, res->ai_addrlen);
    if(rc < 0) {
      perror("connect");
      continue;
    }
    fprintf(stderr, "Connected (%d)\n", fd);
    *(unsigned short*)res->ai_addr = htons(*(unsigned short*)res->ai_addr);
    rc = send(fd, res->ai_addr, res->ai_addrlen, 0);
    *(unsigned short*)res->ai_addr = ntohs(*(unsigned short*)res->ai_addr);
    if(rc < 0) {
      perror("send");
    }
    close(fd);
  }
  freeaddrinfo(res0);
}

listen_sockaddr.cc:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <cstdio>
#include <cerrno>
#include <cstdlib>
#include <poll.h>
#include <vector>
#include <arpa/inet.h>

int main (int ac, char **av) {

  if(ac != 2) {
    fprintf(stderr, "Usage: %s portnumber\n", *av);
    return 1;
  }

  struct addrinfo *res0;
  struct addrinfo hints = { 0, 0, SOCK_DGRAM };
  int rc = getaddrinfo(0, av[1], &hints, &res0);
  if(rc) {
    fprintf(stderr, "%s/%s: %s\n", av[1], av[2], gai_strerror(rc));
    return 1;
  }

  char *name = res0->ai_canonname;
  std::vector<pollfd> fds;
  for(struct addrinfo *res = res0; res; res=res->ai_next) {
    fprintf(stderr, "%s: ", name);
    int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if(fd < 0) {
      perror("socket");
      continue;
    }

    rc = bind(fd, res->ai_addr, res->ai_addrlen);
    if(rc < 0) {
      perror("bind");
      continue;
    }
    fprintf(stderr, "Bound (%d)\n", fd);
    fds.push_back(pollfd({fd, POLLIN}));
  }
  freeaddrinfo(res0);

  while( (rc = poll( &fds[0], fds.size(), -1)) > 0 ) {
    for(size_t i = 0; i < fds.size(); ++i) {
      pollfd& pfd = fds[i];
      if(!pfd.revents)
        continue;
      pfd.revents = 0;

      union {
        sockaddr s;
        sockaddr_in sin;
        sockaddr_in6 sin6;
      } u;
      rc = recv(pfd.fd, &u, sizeof u, 0);
      if(rc < 0) {
        perror("recv");
        continue;
      }
      fprintf(stderr, "Received %d bytes\n", rc);

      char str[256];
      switch(ntohs(u.s.sa_family)) {
      case AF_INET:
        if(inet_ntop(AF_INET, &u.sin.sin_addr, str, sizeof str)) {
          fprintf(stderr, "AF_INET %s\n", str);
        } else {
          fprintf(stderr, "AF_INET unknown\n");
        }
        break;
      case AF_INET6:
        if(inet_ntop(AF_INET6, &u.sin6.sin6_addr, str, sizeof str)) {
          fprintf(stderr, "AF_INET6 %s\n", str);
        } else {
          fprintf(stderr, "AF_INET6 unknown\n");
        }
        break;
      default:
        fprintf(stderr, "UNKNOWN\n");
        break;
      }
    }
  }
}
0 голосов
/ 06 марта 2012

На самом деле IP-адреса сами по себе не являются числами, поэтому представление байтов всегда будет следовать за Big-Endian. По крайней мере, я не знаю ни одной платформы, где это отличается. Он не обрабатывается как число, а как 4 байта.

...