专 门用来存储IP地址,对于IPv4来说,IP地址为32位无符号整数。其定义如下:注:in是internet缩写。
struct in_addr {
unsigned long s_addr;
}
具体在
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
struct sockaddr_in { /* in表示Internet */
unsigned short int sin_family; /* Internet地址族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* Internet地址 */
char sin_zero[8]; /* 填充0(保持与struct sockaddr 一样大小) */
};
具体在
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
/* Notes */
/* bits/sockaddr.h */
typedef unsigned short int sa_family_t;
#define __SOCKADDR_COMMON(sa_prefix) \
sa_family_t sa_prefix##family
#define __SOCKADDR_COMMON_SIZE (sizeof(unsigned short int))
其中一个值得注意的是32位IPv4地址存在两种不同的访问方法。举例来说,如果serv定义为某个网际套接字地址结构,struct sockaddr {
sa_family_t sa_family; /* 地址族, AF_xxx */
char sa_data[14]; /* 14字节的协议地址 */
}
于是套接字函数定义为以指向某个通用套接字地址结构的一个指针作为其参数之一,这正如bind函数的ANSI C函数原型所示:
int bind(int, struct sockaddr *, socklen_t);
这就要求对这些函数的任何调用都必须要将指向特定于协议的套接字地址结构的指针进行类型强制转换(casting),struct sockaddr_in myad;
memset(&myad, 0, sizeof(myad));
B. 然后,给这个结构变量赋值,代码如下:
myad.sin_family = AF_INET;
myad.sin_port = htons(8080);
myad.sin_addr.s_addr = htonl(INADDR_ANY);
C. 在进行函数调用时,将这个结构强制转换为struct sockaddr类型,代码如下:
bind(serverFd, (struct sockaddr *) &myad, sizeof(myad));
附:Socket常用数据类型说明:
struct in6_addr {
uint8_t s6_addr[16]; /* 128-bit IPv6 address */
/* network byte ordered */
}
#define SIN6_LEN /* required for compile-time tests */
struct sockaddr_in6 {
uint8_t sin6_len; /* length of this struct (28) */
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* transport layer port# */
/* network byte ordered */
uint32_t sin6_flowinfo; /* flow information, undefined */
struct in6_addr sin6_addr; /* IPv6 address */
/* network byte ordered */
uint32_t sin6_scope_id; /* set of interfaces for a scope */
}
具体在/* IPv6 address */
struct in6_addr
{
union
{
uint8_t __u6_addr8[16];
#if defined __USE_MISC || defined __USE_GNU
uint16_t __u6_addr16[8];
uint32_t __u6_addr32[4];
#endif
} __in6_u;
#define s6_addr __in6_u.__u6_addr8
#if defined __USE_MISC || defined __USE_GNU
# define s6_addr16 __in6_u.__u6_addr16
# define s6_addr32 __in6_u.__u6_addr32
#endif
};
/* Ditto, for IPv6. */
struct sockaddr_in6
{
__SOCKADDR_COMMON (sin6_);
in_port_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; /* IPv6 scope-id */
};
整形字节序转换函数原型及其说明如下表所示:
注:h: host; n: network; s: short; l: long。
* 大端和小端 科普 *
1)小端就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2)大端就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:
A. 大端模式:
低地址 -----------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
B. 小端模式:
低地址 ------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
inet_pton函数原型如下[将"点分十进制" -> "整数"]
#include
#include
#include
int inet_pton(int af, const char *src, void *dst);
//这个函数转换字符串到网络地址,第一个参数af是地址族,转换后存在dst中
//若成功则返回1;若输入不是有效的表达式则返回0;若出错则返回-1。
inet_pton是inet_addr的扩展,支持的多地址族有下列:
#include
#include
#include
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
//这个函数转换网络二进制结构到ASCII类型的地址,参数的作用和上面相同,只是多了一个参数socklen_t cnt,
//它是所指向缓存区dst的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC。
//若成功则返回指向结果的指针,若出错则返回NULL。
如果以不被支持的地址族作为family参数,这两个函数就都返回一个错误,并将errno设置为EAFNOSUPPORT。
#include
#include
#include
#include
#include
#include
int main (void)
{
char IPdotdec[20]; // 存放点分十进制IP地址
struct in_addr s; // IPv4地址结构体
// 输入IP地址
printf("Please input IP address: ");
scanf("%s", &IPdotdec);
// 转换
inet_pton(AF_INET, IPdotdec, (void *)&s);
printf("inet_pton: 0x%x\n", s.s_addr); // 注意得到的字节序
// 反转换
inet_ntop(AF_INET, (void *)&s, IPdotdec, 16);
printf("inet_ntop: %s\n", IPdotdec);
}
(该函数无法处理255.255.255.255的IP地址,已弃用)
转载链接:http://www.cnblogs.com/xiehongfeng100/p/4597803.html