我有一个在Linux上使用Berkley套接字API的C ++程序。我有一端连接向客户端发送两个IP地址。我可以使用inet_ntop()
和inet_pton()
来表示这些内容,但这会使消息长度为2*INET6_ADDRSTRLEN
,即92
个字节。两个IP地址似乎有点多。是否存在可移植的,紧凑的IP地址二进制表示(它必须同时适用于IPv4和IPv6)。
答案 0 :(得分:0)
实际上,IP地址本身不是数字,因此字节表示将始终遵循Big-Endian。至少我不知道这有什么不同的平台。它只是作为一个数字处理,而是作为4个字节处理。
答案 1 :(得分:0)
如果你有一个addrinfo,那么发送.ai_addr
和.ai_addrlen
。
试试这两个程序:
#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);
}
#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;
}
}
}
}