Linuxでよく見られるipアドレスおよびsocketアドレス表現方法
6086 ワード
最近、IPアドレスやsocketアドレスとの付き合いが多く、いくつかの一般的なソケットに遭遇しました. である.
様々なプロトコルを統一するために、socket対応インタフェースは、
図中、
Linuxネットワークプログラミングでは、どのプロトコルを使用するも、同じsocket APIが使用されるが、各プロトコルがネットワークアドレスを表す構造体は異なり、例えばIPv 4が
一般的な汎用socket構造体に関するAPIは、次のとおりです.
では、なぜ
共通のアドレスデータ構造として、その大きさはすべての具体的なプロトコルアドレス構造の大きさの最大値であるが、
複数のプロトコルに関するネットワークプログラミングでは、
IPv 4/IPv 6ハイブリッドプログラミングのDemo:
https://www.cnblogs.com/tanghuimin0713/p/3425936.html
https://blog.csdn.net/weixin_44874963/article/details/89395292
sockaddr_in
-ipv 4アドレス、number表記法4バイトでよい、例えば字面量表記法は「255.255.255.255.255.255」であり、デジタル表記法に移行し、ff.ff.ff.ff
=>ffffffff
sock_addr_in6
--ipv 6アドレス、number表現法16バイトでsockaddr
--一般的なsocket APIのsocketアドレス汎用表現、16バイトsockaddr_storage
--ipv 6に互換性のあるsocketアドレスの汎用表現であり、28バイトのIPv4 address
およびSocket address for IPv4
、in_addr
は4バイト、IPv 4のSocket address
は16バイトtypedef __uint8_t sa_family_t;
typedef __uint16_t in_port_t;
typedef __uint32_t in_addr_t; /* base type for internet address */
/*
* Internet address (a structure for historical reasons)
* Ipv4 ,
*/
struct in_addr {
in_addr_t s_addr;
};
/*
* Socket address, internet style.
*/
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
IPv6 address
およびSocket address for IPv6
、IPv 6のSocket address
は28バイトtypedef __uint8_t sa_family_t;
typedef __uint16_t in_port_t;
/*
* IPv6 address 16 128bit
*/
typedef struct in6_addr {
union {
__uint8_t __u6_addr8[16];
__uint16_t __u6_addr16[8];
__uint32_t __u6_addr32[4];
} __u6_addr; /* 128-bit IP6 address */
} in6_addr_t;
#define s6_addr __u6_addr.__u6_addr8
#define INET6_ADDRSTRLEN 46
/*
* Socket address for IPv6
*/
struct sockaddr_in6 {
__uint8_t sin6_len; /* length of this struct(sa_family_t) */
sa_family_t sin6_family; /* AF_INET6 (sa_family_t) */
in_port_t sin6_port; /* Transport layer port # (in_port_t) */
__uint32_t sin6_flowinfo; /* IP6 flow information */
struct in6_addr sin6_addr; /* IP6 address */
__uint32_t sin6_scope_id; /* scope zone index */
};
様々なプロトコルを統一するために、socket対応インタフェースは、
sockaddr(16 )
およびsockaddr_storage(128 )
の2つの汎用ソケットの構造体を定義し、sockaddr_storage
は、sockaddr_in6(128 )
のような比較的長いプロトコルに適合するために後に定義され、sockaddr_storage
のような汎用ソケットを使用する必要がある場合、sockaddr
に強く転換し、長さはsizeof(struct sockaddr_storage)
である.図中、
struct sockaddr
は16バイト、struct sockaddr_storage
は28バイト/*
* [XSI] Structure used by kernel to store most addresses.
*/
struct sockaddr {
__uint8_t sa_len; /* total length */
sa_family_t sa_family; /* [XSI] address family */
char sa_data[14]; /* [XSI] addr value (actually larger) */
};
/*
* RFC 2553: protocol-independent placeholder for socket addresses
*/
#define _SS_MAXSIZE 128
#define _SS_ALIGNSIZE (sizeof(__int64_t))
#define _SS_PAD1SIZE \
(_SS_ALIGNSIZE - sizeof(__uint8_t) - sizeof(sa_family_t))
#define _SS_PAD2SIZE \
(_SS_MAXSIZE - sizeof(__uint8_t) - sizeof(sa_family_t) - \
_SS_PAD1SIZE - _SS_ALIGNSIZE)
/*
* [XSI] sockaddr_storage
*/
struct sockaddr_storage {
__uint8_t ss_len; /* address length */
sa_family_t ss_family; /* [XSI] address family */
char __ss_pad1[_SS_PAD1SIZE];
__int64_t __ss_align; /* force structure storage alignment */
char __ss_pad2[_SS_PAD2SIZE];
};
Linuxネットワークプログラミングでは、どのプロトコルを使用するも、同じsocket APIが使用されるが、各プロトコルがネットワークアドレスを表す構造体は異なり、例えばIPv 4が
struct sockaddr_in
、IPv 6がstruct sockaddr_in6
であるため、これらのネットワークアドレスを表す構造体をすべて共通の構造体に抽象化する必要があり、抽象化後の構造体はstruct sockaddr
である.一般的な汎用socket構造体に関するAPIは、次のとおりです.
/*application->kernel*/
int bind (int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
int connect(int sockfd, const struct sockaddr *serv_addr,
socklen_t addrlen);
int sendto (int s, const void *msg, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen);
/*kernel->application*/
int accept (int s, struct sockaddr *addr, socklen_t *addrlen);
int recvfrom (int s, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
int getpeername(int s, struct sockaddr *name, socklen_t *namelen);
int getsockname(int s, struct sockaddr *name, socklen_t *namelen);
では、なぜ
struct sockaddr_storage
という汎用構造体が現れたのでしょうか.共通のアドレスデータ構造として、その大きさはすべての具体的なプロトコルアドレス構造の大きさの最大値であるが、
sizeof(struct sockaddr) = 16
、sizeof(struct sockaddr_in6) = 28
、struct sockaddr
という共通のデータ構造holdはIPv 6に耐えられないことは明らかである.複数のプロトコルに関するネットワークプログラミングでは、
struct sockaddr_storage
という構造体で通信アドレスを表し、socket APIを呼び出す場合、struct sockaddr_storage
強制タイプをstruct sockaddr_storage
に変換する必要があり、アドレス長はstruct sockaddr
である.次のようになります.struct sockaddr_storage addr;
/*
*/
sendto (s, *msg, len, flags, (struct sockaddr *)&addr, sizeof(struct sockaddr_storage));
IPv 4/IPv 6ハイブリッドプログラミングのDemo:
struct sockaddr_storage addr;
memset(&addr, 0, sizeof(struct sockaddr_storage));
if (isIPv6 == TRUE)
{
struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6 *)&addr;
addr_v6->sin6_family = AF_INET6;
addr_v6->sin6_port = 1234;
inet_pton(AF_INET6, “2001:3211::1”, &(addr_v6->sin6_addr));
}
else
{
struct sockaddr_in *addr_v4 = (struct sockaddr_in *)&addr;
addr_v4->sin_family = AF_INET;
addr_v4->sin_port = 1234;
inet_aton(“192.168.1.228”, &(addr_v4->sin_addr));
}
sendto(sock, buf, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_storage));
参考文献
https://www.cnblogs.com/tanghuimin0713/p/3425936.html
https://blog.csdn.net/weixin_44874963/article/details/89395292