套接字地址结构
#include <arpa/inet.h>
struct sockaddr_in
{
sa_family_t sin_family; //地址族
in_port_t sin_port; //端口号
struct in_addr sin_addr; //IP 地址
unsigned char sin_zero[8]; //不使用
};
地址族
名称 | 地址族 |
---|---|
AF_INET | IPv4 网络协议中使用的地址族 |
AF_INET6 | IPv6 网络协议中使用的地址族 |
AF_LOCAL | 本地通信中采用 UNIX 协议的地址族 |
端口号
端口号是一个 16 位无符号整数。可分配的端口号范围是 0 ~ 65535。其中,0 ~ 1023 是知名端口号。
IP 地址
一个 IP 地址就是一个 32 位无符号整数。
#include <arpa/inet.h>
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
注:端口号和 IP 地址应采用大端序。
网络字节序
CPU 向内存中保存数据的方式有以下 2 种。
- 大端序:高位字节存放到低位地址。
- 小端序:高位字节存放到高位地址。
大端序 CPU 保存 0x12345678 的方式如下。
0x12 | 0x34 | 0x56 | 0x78 |
---|
小端序 CPU 保存 0x12345678 的方式如下。
0x78 | 0x56 | 0x34 | 0x12 |
---|
因为因特网主机可以有不同的主机字节顺序,所以 TCP/IP 为任意整数数据项定义了统一的网络字节顺序,即大端序。
字节序转换函数
#include <arpa/inet.h>
uint32_t htonl(uint32_t __hostlong);
// 将 32 位整数由主机字节顺序转换为网络字节顺序
uint16_t htons(uint16_t __hostshort);
// 将 16 位整数由主机字节顺序转换为网络字节顺序
uint32_t ntohl(uint32_t __netlong);
// 将 32 位整数由网络字节顺序转换为主机字节顺序
uint16_t ntohs(uint16_t __netshort);
// 将 16 位整数由网络字节顺序转换为主机字节顺序
例:
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
printf("host_port:%x \n", 0x1234);
printf("net_port:%x \n", htons(0x1234));
printf("host_addr:%x \n", 0x12345678);
printf("net_addr:%x \n", htonl(0x12345678));
return 0;
}
host_port:1234
net_port:3412
host_addr:12345678
net_addr:78563412
网络地址转换函数
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *inp);
// 将点分十进制表示转换为十六进制数
char *inet_ntoa(struct in_addr in);
// 将十六进制数转换为点分十进制表示
例:
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
struct sockaddr_in addr;
inet_aton("10.10.1.1", &addr.sin_addr);
printf("%x\n", ntohl(addr.sin_addr.s_addr));
printf("%x\n", ntohl(inet_addr("10.10.1.1")));
return 0;
}
a0a0101
a0a0101
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
struct in_addr addr;
addr.s_addr = htonl(0x0a0a0101);
printf("%s\n", inet_ntoa(addr));
return 0;
}
10.10.1.1