专 门用来存储IP地址,对于IPv4来说,IP地址为32位无符号整数。其定义如下:注:in是internet缩写。
struct in_addr { unsigned long s_addr; }
具体在<netinet/in.h>的定义是这样子的:
/* Internet address. */ typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; };具体在<netinet/in.h>的定义是这样子的:
/* 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定义为某个网际套接字地址结构, 那么serv.sin_addr将按in_addr结构引用其中的32为IPv4地址,而serv.sin_addr_s_addr将按in_addr_t(通常是一个无符号的32 位整数)引用同一个32位IPv4地址。因此,我们必须正确使用IPv4地址,尤其是将它作为函数的参数时,因为编译器对传递结构和传递整数的处理是完全不一样的。 sin_addr字段是一个结构,而不仅仅是一个in_addr_t类型的无符号长整数,这是有历史原因的。早期的版本(4.2BSD)把 in_addr结构定义为多种结构的联合(union),允许访问一个32位IPv4地址中的所有4个字节,或者访问它的2个16位值。这用在 地址被划分成A、B和C三类的时期,便于获取地址中的适当字节。然而随着子网划分技术的来临和无类地址编排的出现,各种地址类正在消失,那个联合已不再需要了。如今大多数系统已经废除了该联合,转而把in_addr定义为仅有一个in_addr_t字段的结构。
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 */ } 具体在<netinet/in.h>头文件定义如下: /* 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 <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> int inet_pton(int af, const char *src, void *dst); //这个函数转换字符串到网络地址,第一个参数af是地址族,转换后存在dst中 //若成功则返回1;若输入不是有效的表达式则返回0;若出错则返回-1。 inet_pton是inet_addr的扩展,支持的多地址族有下列: af = AF_INET src为指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址转换为in_addr的结构体,并复制在*dst中 af = AF_INET6 src为指向IPV6的地址,函数将该地址转换为in6_addr的结构体,并复制在*dst中
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> 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
