#include <netinet/in.h> struct sockaddr_in { __uint8_t sin_len; //结构体长度,这里为16。(1 + 1 + 2 + 4 + 8 = 16) sa_family_t sin_family; //协议族类型,一般为AF_INET。实际上是__uint8_t,占1字节。 in_port_t sin_port; //端口号 最大65535 占2字节 struct in_addr sin_addr; //这里存放的是IP地址,结构体定义在下方 占4字节char sin_zero[8]; //预留的空间,一般置0,占8字节}; }; struct in_addr { in_addr_t s_addr; //in_addr_t是__uint32_t的typedef。 占4字节 };
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 128bit的IP地址*/ __uint32_t sin6_scope_id; /* scope zone index v6相关的信息*/ }; /*in6_addr在Mac OS 中的定义*/ 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在POSIX中的定义*/ struct in6_addr { union { __uint8_t __u6_addr8[16]; } __u6_addr; /* 128-bit IP6 address */ };
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) */ };通过比较通用套接字结构体和v4、v6套接字结构体,可以看出前两个变量长度是一样的,第三个变量一个char数组。之前看到有网友讨论sa_data[14]装不下v6的地址,其实是对结构体指针强转性质不太熟悉。强转成sockaddr*指针后,sa_data[x]指向的是原结构体内部的不同偏移量所在的单元。如果是ipv6强转过来的话,sa_data[7]就可以寻址到v6地址结构体的in6_addr,从而获取地址。原帖见http://bbs.csdn.net/topics/380026132?page=1。下面是我做的一个测试:
#include <iostream> struct sockaddr { uint8_t sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ }; struct in6_addr { union { char __u6_addr8[16]; } __u6_addr; /* 128-bit IP6 address */ }; struct sockaddr_in6 { unsigned short int sin6_family; /* AF_INET6 */ uint16_t sin6_port; /* Transport layer port # */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ uint32_t sin6_scope_id; /* scope id (new in RFC2553) */ }; int main(int argc, const char * argv[]) { struct sockaddr_in6 sk_in6; std::cout<<"size of sin6_family = "<<sizeof(sk_in6.sin6_family)<<std::endl; for(int i = 0;i < 16;++i){ sk_in6.sin6_addr.__u6_addr.__u6_addr8[i] = ‘3‘; } for(int i = 0;i < 16;++i){ std::cout<<sk_in6.sin6_addr.__u6_addr.__u6_addr8[i]<<std::endl; } std::cout<<"---------"<<std::endl; struct sockaddr *_sockaddr = (sockaddr*)&sk_in6; struct in6_addr *_in6_addr = (in6_addr*)&_sockaddr->sa_data[7]; for(int i = 0;i < 16;++i){ std::cout<<_in6_addr->__u6_addr.__u6_addr8[i]<<std::endl; } return 0; }
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]; };
我个人将基本的socket函数分为两类,一类是工具类,主要用来做一些字节排序或者地址转换等简单的操作,不涉及到功能的。另一类就是功能类。
#define ntohs(x) __DARWIN_OSSwapInt16(x) #define htons(x) __DARWIN_OSSwapInt16(x) #define ntohl(x) __DARWIN_OSSwapInt32(x) #define htonl(x) __DARWIN_OSSwapInt32(x)在大端系统中,这些函数直接定义成空宏就行了。
int bcmp(const void *, const void *, size_t) __POSIX_C_DEPRECATED(200112L); void bcopy(const void *, void *, size_t) __POSIX_C_DEPRECATED(200112L); void bzero(void *, size_t) __POSIX_C_DEPRECATED(200112L);
程序中往往是通过字符串来定义IP地址的,要在网络中传输首先要将字符串转换为网络字节序的IP地址,其实这里隐含了一个字节排序过程。
旧式的转换函数这里就不讲了,因为对v6地址不通用,虽然我在windows程序开发中还经常使用他们。甚至用到了项目当中,目测它们不会在v6的环境下被用到,哈哈。
int inet_pton(int family, const char * strptr, void *addrptr);
const char *inet_ntop(int family, const void *addr, char *strptr, socklen_t len);
原文:http://blog.csdn.net/jedihy/article/details/18678393