是不是结构sockadr_in应该为IPv4和IPv6工作? [英] Isn't struct sockadr_in supposed to work for both IPv4 and IPv6?

查看:205
本文介绍了是不是结构sockadr_in应该为IPv4和IPv6工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具体地说sin_addr似乎是位于为解决IPv4和IPv6插座不同的存储器位置。这导致怪事:

 的#include<&stdio.h中GT;
#包括LT&; netinet / in.h中>INT主(INT ARGC,字符** argv的){
  结构SOCKADDR_IN SA;
  的printf(sin_addr在SOCKADDR_IN =%P \\ N,&安培; sa.sin_addr);
  的printf(sin_addr sockaddr_in6的=%P \\ N,及((结构* sockaddr_in6的)及SA) - GT; sin6_addr);
};

输出:

  sin_addr在SOCKADDR_IN = 0x7fffa26102b4
sin_addr sockaddr_in6的= 0x7fffa26102b8

为什么没有这2值相同?

由于这是指向同一数据(地址连接到),​​这应该是位于相同的地址。不然,怎么是你应该打电话给inet_ntop与你不知道的是IPv4或一个SOCKADDR_IN IPv6的?


解决方案

  

为什么没有这2值相同?


SOCKADDR_IN 体sockaddr_in6 是用于不同的地址族(分别为IPv4和IPv6)的不同结构。它们不要求以任何方式彼此相容除了一个 - 第一场必须是16位整数来保存地址族。 SOCKADDR_IN 总是有一个字段设置为 AF_INET 体sockaddr_in6 总是有一个字段设置为 AF_INET6 。通过这样的标准化家庭领域,任何的sockaddr 基于API可以访问该字段,并知道如何跨preT的结构数据的其余部分需要。这也是为什么的sockaddr 基于API的通常也有一个 INT 尺寸值作为输入/输出为好,因为 SOCKADDR_IN 体sockaddr_in6 是不同的字节大小,这样的API需要能够验证你绕过任何缓冲区的大小。


  

由于这是指向同一数据(地址连接到),​​这应该是位于相同的地址。


没有,它不应该。该结构内的地址字段的位置是特定的结构属于地址族的类型。有没有要求 SOCKADDR_IN 体sockaddr_in6 应在各自的地址存储完全相同的偏移量。


  

不然,怎么是你应该打电话给inet_ntop与你不知道的是IPv4或一个SOCKADDR_IN IPv6的?


SOCKADDR_IN 只能用IPv4和没有别的,和体sockaddr_in6 只能使用IPv6并没有什么二手其他。如果你有一个 SOCKADDR_IN 那么你implicitally知道你有一个IPv4地址,如果你有一个体sockaddr_in6 那么你implicitally知道你有一个IPv6地址。你必须指定inet_ntop这些信息()所以它知道如何跨preT数据你给它:

 结构SOCKADDR_IN SA;
inet_ntop(AF_INET,及(sa.sin_addr),...);

 结构SA sockaddr_in6的;
inet_ntop(AF_INET6,及(sa.sin6_addr),...);

要帮你写家庭无关code,你应该使用 sockaddr_storage 而不是 SOCKADDR_IN 体sockaddr_in6 直接在可能的情况。 sockaddr_storage 足够大的规模同时容纳 SOCKADDR_IN 体sockaddr_in6 结构。由于这两种结构的同时定义了一个家庭领域的偏移和大小, sockaddr_storage 可与上 SOCKADDR * 指针(连接()接受()绑定() getsockname() getpeername()等)。

然而, inet_ntop()不属于这一类,所以你要拉开一个 sockaddr_storage 手动当使用 inet_ntop(),例如:

 结构sockaddr_storage SA;开关(((SOCKADDR *)及SA) -  GT;上sa_family)
{
    案例AF_INET:
        inet_ntop(AF_INET,及(((* SOCKADDR_IN)及SA) - GT; sin_addr),...);
        打破;
    案例AF_INET6:
        inet_ntop(AF_INET6,及(((sockaddr_in6的*)及SA) - > sin6_addr),...);
        打破;
}

Specifically sin_addr seems to be located on different memory locations for IPv4 and IPv6 socket addressed. This results in weirdness:

#include <stdio.h>                                                                               
#include <netinet/in.h>                                                                          

int main(int argc, char ** argv) {                                                               
  struct sockaddr_in sa;                                                                         
  printf("sin_addr in sockaddr_in  = %p\n", &sa.sin_addr);                                       
  printf("sin_addr in sockaddr_in6 = %p\n", &((struct sockaddr_in6*)&sa)->sin6_addr);            
};

Output:

sin_addr in sockaddr_in  = 0x7fffa26102b4
sin_addr in sockaddr_in6 = 0x7fffa26102b8

Why aren't these 2 values the same ?

Since this is pointing to the same data (the address to connect to), this should be located at the same address. Otherwise, how are you supposed to call inet_ntop with a sockaddr_in that you don't know is IPv4 or IPv6 ?

解决方案

Why aren't these 2 values the same ?

sockaddr_in and sockaddr_in6 are different structs used for different address families (IPv4 and IPv6, respectively). They are not required to be compatible with each other in any way except one - the first field must be a 16-bit integer to hold the address family. sockaddr_in always has that field set to AF_INET, and sockaddr_in6 always has that field set to AF_INET6. By standardizing the family field in this way, any sockaddr-based API can access that field and know how to interpret the rest of the struct data as needed. That is also why sockaddr-based APIs usually also have an int size value as input/output as well, since sockaddr_in and sockaddr_in6 are different byte sizes, so APIs need to be able to validate the size of any buffers you pass around.

Since this is pointing to the same data (the address to connect to), this should be located at the same address.

No, it should not. The location of the address field within the struct is specific to the type of address family the struct belongs to. There is no requirement that sockaddr_in and sockaddr_in6 should store their addresses at the exact same offset.

Otherwise, how are you supposed to call inet_ntop with a sockaddr_in that you don't know is IPv4 or IPv6 ?

sockaddr_in can only be used with IPv4 and nothing else, and sockaddr_in6 can only be used with IPv6 and nothing else. If you have a sockaddr_in then you implicitally know you have an IPv4 address, and if you have a sockaddr_in6 then you implicitally know you have an IPv6 address. You have to specify that information to inet_ntop() so it knows how to interpret the data you pass in to it:

struct sockaddr_in sa;
inet_ntop(AF_INET, &(sa.sin_addr), ...);

.

struct sockaddr_in6 sa;
inet_ntop(AF_INET6, &(sa.sin6_addr), ...);

To help you write family-agnostic code, you should be using sockaddr_storage instead of sockaddr_in or sockaddr_in6 directly when possible. sockaddr_storage is large enough in size to hold both sockaddr_in and sockaddr_in6 structs. Since both structs define a family field at the same offset and size, sockaddr_storage can be used with any API that operates on sockaddr* pointers (connect(), accept(), bind(), getsockname(), getpeername(), etc).

However, inet_ntop() does not fall into that category, so you have to pull apart a sockaddr_storage manually when using inet_ntop(), eg:

struct sockaddr_storage sa;

switch (((sockaddr*)&sa)->sa_family)
{
    case AF_INET:
        inet_ntop(AF_INET, &(((sockaddr_in*)&sa)->sin_addr), ...);
        break;
    case AF_INET6:
        inet_ntop(AF_INET6, &(((sockaddr_in6*)&sa)->sin6_addr), ...);
        break;
}

这篇关于是不是结构sockadr_in应该为IPv4和IPv6工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆