IP地址信息结构体
此数据结构用做 bind、connect、recvfrom、sendto 等函数的参数,指明地址信息。但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构(sockaddr_in
,sockaddr_in6
)
struct sockaddr {
unsigned short sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
sa_family(地址族,也就是 IP 地址类型) | 值 | 解释 |
---|---|---|
AF_INET | 2 | AF 是"Address Family"的简写,INET是"Inetnet"的简写。AF_INET 表示 IPv4 地址,例如 127.0.0.1 |
AF_INET6 | 23 | 表示 IPv6 地址,例如 1030::C9B4:FF12:48AA:1A2B |
AF_UNSPEC | 0 | 协议无关 |
IPV4地址信息结构体
struct sockaddr_in {
short int sin_family; /* Address family; must be AF_INET. */
unsigned short int sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
unsigned char sin_zero[8]; /* Same size as struct sockaddr */ //是为了让 sockaddr 与 socketaddr_in 两个数据结构保持大小相同而保留的空字节
};
struct in_addr {
uint32_t s_addr; //ip地址 通过 inet_addr(ipstr) 将一个点分十进制的IP(eg:192.168.1.101)转换成一个长整数型数
};
IPV6地址信息结构体
struct sockaddr_in6 {
short sin6_family; /* Address family; must be AF_INET6. */
u_short sin6_port; /* Transport-level port number */
u_long sin6_flowinfo; /* Ipv6 flow information. */
struct in6_addr sin6_addr; /* Ipv6 address. */
u_long sin6_scope_id; /* Set of interfaces for a scope. */
};
struct in6_addr {
union {
u_char Byte[16]; /* Host address formatted as 16 u_chars. */
u_short Word[8]; /* Host address formatted as 8 u_shorts. */
} u;
};
addrinfo结构体
struct addrinfo {
int ai_flags; /* customize behavior */
int ai_family; /* address family */
int ai_socktype; /* socket type */
int ai_protocol; /* protocol */
size_t ai_addrlen; /* length in bytes of address */
struct sockaddr *ai_addr; /* address */
char *ai_canonname; /* canonical name of host */
struct addrinfo *ai_next; /* next in list */
};
ai_flags | 值 | 解释 |
---|---|---|
AI_ADDRCONFIG | 32 | 查询配置的地址类型(IPV4或IPV6) |
AI_ALL |
16 | 查找IPV4和IPV6地址 |
AI_PASSIVE |
1 | 套接字地址用于监听绑定 |
AI_CANONNAME | 2 | 用于返回主机的规范名称 |
AI_NUMERICHOST | 4 | 地址为数字串 |
ai_protocol
协议(Protocol)就是网络通信的约定,通信的双方必须都遵守才能正常收发数据。协议有很多种,例如 TCP、UDP、IP 等,通信的双方必须使用同一协议才能通信。协议是一种规范,由计算 机组织制定,规定了很多细节,例如,如何建立连接,如何相互识别等。
协议仅仅是一种规范,必须由计算机软件来实现。例如 IP 协议规定了如何找到目标计算机,那么各个开发商在开发自己的软件时就必须遵守该协议,不能另起炉灶。
所谓协议族(Protocol Family),就是一组协议(多个协议)的统称。最常用的是 TCP/IP 协议族,它包含了 TCP、IP、UDP、Telnet、FTP、SMTP 等上百个互为关联的协议,由于 TCP、IP 是两种常用的底层协议,所以把它们统称为 TCP/IP 协议族。
ai_socktype(数据传输协议) | 值 | 解释 |
---|---|---|
IPPROTO_IP | 0 | IP协议 |
IPPROTO_IPV4 | 4 | IPv4 |
IPPROTO_IPV6 | 41 | IPv6 |
IPPROTO_UDP | 17 | UDP 传输协议 |
IPPROTO_TCP | 6 | TCP 传输协议 |
ai_socktype(数据传输方式) | 值 | 解释 |
---|---|---|
SOCK_STREAM | 1 | 表示面向连接的数据传输方式。 |
SOCK_DGRAM | 2 | 表示无连接的数据传输方式 |
getaddrinfo() 函数
getaddrinfo()
函数能够处理域名到IP地址以及进程服务名到端口这两种转换,返回的是一个sockaddr
结构的链表而不是一个地址清单。这些sockaddr
结构随后可由套接口
函数直接使用。
如此一来,getaddrinfo
函数把协议相关性安全隐藏在这个库函数内部。应用程序只要处理由getaddrinfo
函数填写的套接口地址结构。
int getaddrinfo(
const char *node,
const char *service,
const struct addrinfo *hints,
struct addrinfo **res
);
node
:指向一个主机名(域名)或者地址串(IPv4的点分十进制串或者IPv6的16进制串)。
service
:指向一个10进制端口号数串,或者是已定义的服务名称,如ftp、http等。
node,service 不能同时为NULL。
hints
:它可以是一个空指针,也可以是一个指向某个addrinfo结构的指针,调用者在这个结构中填入关于期望返回的信息类型的线索。
Linux下一切皆为文件
在 Linux 中,一切都是文件,除了文本文件、源文件、二进制文件等,一个硬件设备也可以被映射为一个虚拟的文件,称为设备文件。例如,stdin
称为标准输入文件,它对应的硬件设备一般
是键盘,stdout
称为标准输出文件,它对应的硬件设备一般是显示器。对于所有的文件,都可以使用 read()
函数读取数据,使用 write()
函数写入数据。
“一切都是文件”
的思想极大地简化了程序员的理解和操作,使得对硬件设备的处理就像普通文件一样。所有在 Linux 中创建的文件都有一个 int 类型的编号
,称为文件描述符(File Descriptor)。
使用文件时,只要知道文件描述符就可以。例如,stdin 的描述符为 0,stdout 的描述符为 1
。
在 Linux 中,socket
也被认为是文件的一种,和普通文件的操作没有区别,所以在网络数据传输过程中自然可以使用与文件 I/O 相关的函数。可以认为,两台计算机之间的通信,实际上是两个 socket 文件的相互读写。