sockaddr
、
sockaddr_in
、
addrinfo
比较
struct sockaddr {
unsigned short sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
sa_family
是地址家族,一般都是“
AF_xxx
”的形式。好像通常大多用的是都是
AF_INET
。
sa_data
是
14
字节协议地址。
此数据结构用做
bind
、
connect
、
recvfrom
、
sendto
等函数的参数,指明地址信
息。
但一般编程中并不直接针对此数据结构操作,而是使用另一个与
sockaddr
等价的
数据结构
sockaddr_in
(在
netinet/in.h
中定义)
:
struct sockaddr_in {
short int sin_family; /* Address family */
unsigned short int sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
unsigned char sin_zero[8]; /* Same size as struct sockaddr */
};
struct in_addr {
unsigned long s_addr;
};
typedef struct in_addr {
union {
struct{
unsigned char s_b1,
s_b2,
s_b3,
s_b4;
} S_un_b;
struct {
unsigned short s_w1,
s_w2;
} S_un_w;
unsigned long S_addr;
} S_un;
} IN_ADDR;
sin_family
指代协议族,在
socket
编程中只能是
AF_INET
sin_port
存储端口号(使用
网络字节顺序
)
sin_addr
存储
IP
地址,使用
in_addr
这个数据结构
sin_zero
是为了让
sockaddr
与
sockaddr_in
两个数据结构保持大小相同而保留的
空字节
。
s_addr
按照
网络字节顺序
存储
IP
地址。
addrinfo
结构是
getaddrinfo
函数
用来保存主机地址信息的结构体。在头文件
Ws2tcpip.h
中定义。
typedef struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char* ai_canonname;
struct sockaddr* ai_addr;
struct addrinfo* ai_next;
} ADDRINFOA, *PADDRINFOA;
ai_flags
:表示
getaddrinfo
要使用的选项,可赋的值在
Winsock2.h
中有定义,
且可以是几个值的组合。
ai_family
:地址族。一般为
AF_INET
。
ai_socktype
:套接字类型。
SOCK_STREAM
,
SOCK_DGRAM
,
SOCK_RAW
,
SOCK_RDM
SOCK_SEQPACKET
。
ai_protocol
:协议类型。可取的值取决于
ai_address
和
ai_socktype
的值。
IPPROTO_TCP
,
IPPROTO_UDP
,
IPPROTO_RM
。
如果
ai_family
置为
AF_IRDA
,则
ai_protocol
必须为
0
。
ai_addrlen
:
ai_addr
指向的缓冲区的字节数。
ai_canonname
:主机的规范化名称(
canonical name
)
。
ai_addr
:指向
sockaddr
结构的指针。
IP
地址的网络字节顺序和机器字节顺序
.
210.25.132.181
属于
IP
地址的
ASCII
表示法,也就是字符串形式。英语叫
做
IPv4 numbers-and-dots notation
。
如果把
210.25.132.181
转换为整数形式,是
3524887733
,这个就是整数形式
的
IP
地址。英语叫做
binary data
。
(其实
binary
是二进制的意思)
Internet
地址用
“
.
”
间隔的地址可有下列几种表达方式:
a.b.c.d
,
a.b.c
,
a.b
,
a
当四个部分都有定值时,每个都解释成一个字节数据,从左到右组成
Internet
四字节地址。
Internet
地址以网络字节顺序返回
(
字节从左到右排列。
请注意,当一个
Internet
地址在
Intel
机器上表示成一个
32
位整型数时,则上述
的字节为“
d.c.b.a
”
。这是因为
Intel
处理器的字节是从右向左排列的。
上述中
的“
a.b.c.d
”就为网络字节顺序,而“
d.c.b.a
”则为机器字节顺序。
ntohs, ntohl, htons,htonl
的比较和详解
ip
地址是
32
位的端口号是
16
位的
。
ntohs =net to host short int 16
位
htons=host to net short int 16
位
ntohs =net to host long int 32
位
htonl=host to net long int 32
位
u_short PASCAL FAR
ntohs
( u_short netshort);
netshort
:一个以网络字节顺序表达的
16
位数。本函数将一个
16
位数由网
络字节顺序转换为
16
位主机字节顺序。
u_short PASCAL FAR
htons
( u_short hostshort);
hostshort
:一个主机字节顺序表达的
16
位数。
本函数将一个
16
位数从主
机字节顺序转换成
16
位网络字节顺序。
u_long PASCAL FAR
htonl
( u_long hostlong);
hostlong
:一个主机字节顺序表达的
32
位数。本
函数
将一个
32
位数从主机
字节顺序转换成
32
位网络字节顺序。
u_long PASCAL FAR
ntohl
( u_long netlong)
;
netlong
:一个以网络字节顺序表达的
32
位数。
本函数将一个
32
位数由
网络字节顺序转换为
32
位的主机字节顺序。
inet_network()
、
inet_addr()
、
inet_aton()
、
inet_ntoa()
int inet_aton(const char *string, struct in_addr *addr);
in_addr_t inet_addr(const char *cp);
in_addr_t inet_network(const char *cp);
char FAR* PASCAL FAR inet_ntoa( struct in_addr in);
函数
inet_addr()
:将
IP
地址从
点数格式转换成无符号长整型。使用方法如下:
ina.sin_addr.s_addr = inet_addr("132.241.5.10");
注意,
inet_addr()
返回的地址已经是网络字节格式,所以你无需再调用
函数
htonl()
。
函数
inet_network()
:
inet_network
和
inet_addr
函数都是用于将字符串形式转
换为整数形式用的,两者区别很小,
inet_addr
返回的整数形式是网络字节序,而
inet_network
返回的整数形式是主机字节序。
函数
int inet_aton(const char *string, struct in_addr *addr);
inet_aton()
是一个改进的方法来将一个字符串
IP
地址转换为一个
32
位的
网络序列
IP
地址。
输入参数
string
包含
ASCII
表示的
IP
地址。
输出参数
addr
是将要用新的
IP
地址更新的结构。
返回值:
如果这个函数成功,函数的
返回值非零。如果输入地址不正确则会返回零。使用这个函数并没有错误码存放
在
errno
中,所以他的值会被忽略。
inet_aton
函数和上面这俩小子的区别就是
在于他认为
255.255.255.255
是有效的,他不会冤枉这个看似特殊的
IP
地址。
inet_aton
函数返回的是网络字节序的
IP
地址。如:
inet_aton("127.0.0.1",&adr_inet.sin_addr))
函数
inet_ntoa()
:将网络地址转换成“
.
”点隔的字符串格式。本函数将一个用
in
参数所表示的
Internet
地址结构转换成以“
.
”
间隔的诸如“
a.b.c.d
”的字
符串形式。
请注意
inet_ntoa()
返回的字符串存放在
WINDOWS
套接口实现所分配的
内存中。
应用程序不应假设该内存是如何分配的。
在同一个线程的下一个
WINDOWS
套接口调用前,数据将保证是有效。返回值:
若无错误发生,
inet_ntoa()
返回一个字符指针。否则的话,返回
NULL
。其中的数据应在下一个
WINDOWS
套接
口调用前复制出来。函数
inet_ntoa()("ntoa"
的含义是
"network to ascii")
,
就像这样:
printf("%s",inet_ntoa(ina.sin_addr));
它将输出
IP
地址。
Inet_pton()
和
inet_ntop()
Linux
下这
2
个
IP
地址转换函数,可以在将
IP
地址在“点分十进制”和“整
数”
之间转换
而且,
inet_pton
和
inet_ntop
这
2
个函数能够处理
ipv4
和
ipv6
。
算是比较新的函数了。
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
中
。
inet_pton
是
inet_addr
的扩展,
支持的多地址族有下列:
af
=
AF_INET
src
为指向字符型的地址,即
ASCII
的地址的首地址(
ddd.ddd.ddd.ddd
格式的)
,
函数将该地址
转换为
in_addr
的结构体,
并复制在
*dst
中
af
=AF_INET6
src
为指向
IPV6
的地址,
,函数将该地址
转换为
in6_addr
的结构体,并复制
在
*dst
中
如果函数出错将返回一个负值,并将
errno
设置为
EAFNOSUPPORT
,
如果参数
af
指定的地址族和
src
格式不对,函数将返回
0
。
inet_ntop
函数原型如下
[
将“点分十进制”
-
>
“整数”
]
#include
<sys/types.h>
#include
<sys/socket.h>
#include
<arpa/inet.h>
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
这个函数转换网络二进制结构到
ASCII
类型的地址,参数的作用和上面相同,只
是多了一个参数
socklen_t cnt,
他是所指向缓存区
dst
的大小,避免溢出,如果
缓存区太小无法存储地址的值,则返回一个空指针,并将
errno
置为
ENOSPC
。
g
ethostbyname
和
gethostbyaddr
这两个函数仅仅支持
IPv4
,
getaddrinfo
函
数能够处理名字到地址以及服务到端口这两种转换,返回的是一个
sockaddr
结构的链表而不是一个地址清单。这些
sockaddr
结构随后可由套接口函数直
接使用。如此以来,
getaddrinfo
函数把协议相关性安全隐藏在这个库函数内
部。应用程序只要处理由
getaddrinfo
函数填写的套接口地址结构。该函数在
POSIX
规范中定义了。
#include<netdb.h>
int
getaddrinfo(
const
char
*hostname,
const
char
*service,
const
struct
addrinfo *hints, struct addrinfo **result );
返回
0
:
成功
返回非
0
:
出错
hostname:
一个主机名或者地址串
(IPv4
的点分十进制串或者
IPv6
的
16
进制串
)
service
:一个服务名或者
10
进制端口号数串。
hints
:可以是一个空指针,也可以是一个指向某个
addrinfo
结构的指针,调
用者在这个结构中填入关于期望返回的信息类型的暗示。举例来说:如果指定
的服务既支持
TCP
也支持
UDP
,
那么调用者可以把
hints
结构中的
ai_socktype
成员设置成
SOCK_DGRAM
使得返回的仅仅是适用于数据报套接口的信息。
本函数通过
result
指针参数返回一个指向
addrinfo
结构链表的指针,而
addrinfo
结构定义在头文件
netdb.h
中:
struct addrinfo{
int ai_flags;
int ai_family;
int ai_socktype;