文章目录
函数
//主机字节序与网络字节序的转换
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);
//IP地址字符串与32位整数型数据的转换
//IP address to network
in_addr_t inet_addr(const char* string);//IP地址字符串=>32位整数型数据 返回32位整数型数据 失败返回INADDR_NONE
int inet_aton(const char *string,struct in_addr *addr);//IP地址字符串=>32位整数型数据(存放在结构体in_addr的addr中) 返回执行结果(1:成功 0:失败)
//network to IP address
char * inet_ntoa(struct in_addr ad);//返回转换的字符串地址值 失败返回-1
地址信息结构
sockaddr_in结构
定义:
struct sockaddr_in{
sa_family_t sin_family;//地址族(address family)
uint16_t sin_port;//16位TCP/UDP端口号
struct in_addr sin_addr;//32位IP地址
char sin_zero[8];//不使用
};
struct in_addr{
In_addr_t s_addr;//32位IPv4地址
}
使用:
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET; //设置地址家族
serv_addr.sin_port = htons(argv[1]); //设置端口
serv_addr.sin_addr.s_addr = htons(atoi[argv[2]); //设置地址
htons(host to network short):将端口号由主机字节序转换为网络字节序的整数值。
//h:host n:network s:short
uint16_t、in_addr_t等类型可参考POSIX(Portable Operating System Interface,可移植操作系统接口)。
POSIX是为UNIX系列操作系统设立的标准,它定义了一些其他数据类型如:
数据类型 | 名称数据类型说明 | 声明的头文件 |
---|---|---|
int8_t | signed 8-bit int | sys/types.h |
uint8_t | unsigned 8-bit int(unsigned char) | sys/types.h |
int16_t | signed 16-bit int | sys/types.h |
uint16_t | unsigned 16-bit int(unsigned short) | sys/types.h |
int32_t | signed 32-bit int | sys/types.h |
uint32_t | unsigned 32-bit int(unsigned long) | sys/types.h |
sa_family_t | 地址族(address family) | sys/socket.h |
socklen_t | 长度(length of struct) | sys/socket.h |
in_addr_t | IP地址,声明为uint32_t | netinet/in.h |
in_port_t | 端口号,声明为uint16_t | netinet/in.h |
sockadr_in变量地址值传递给bind函数:
struct sockaddr_in serv_addr;
...
if(bind(serv_sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr))==-1)
error_handling("bind() error");
sockaddr结构体:
struct sockaddr{
sa_family_t sin_family;//地址族(Address Family)
char sa_data[14];//地址信息
};
sa_data: 需包含IP地址和端口号,剩余部分填充0,此为bind函数要求。这对于包含地址信息而言很麻烦,所以才有了新的结果欧体sockaddr_in
即符合bind函数要求的字节流
sockaddr_in成员分析
sin_family:
每种协议族适用地址族均不同。如IPv4使用4字节地址族,IPv6使用16字节地址族,参考表:
地址族(Address Family) | 含义 |
---|---|
AF_INET | IPv4网络协议中使用的地址族 |
AF_INET6 | IPv6网络协议中使用的地址族 |
AF_LOCAL | 本地通信中采用的UNIX协议的地址族 |
sin_port:
保存16位端口号,重点为,以网络字节序保存。
sin_addr:
保存32位IP地址信息,且也以网络字节序保存。
sin_zero:
无特殊含义,是为了使结构体sockaddr_in大小与sockaddr结构体保持一致而插入的成员。需填充为0
网络字节序与地址变换
网络字节序
CPU保存数据的方式有两种:
大端序(Big Endian):高位字节存放到低位地址
小端序(Little Endian):高位字节存放到高位地址
在通过网络传输数据时约定统一方式,这种约定称为网络字节序(Network Byte Order),非常简单:统一为大端序。(先将数据数组转化为大端序格式再进行网络传输。
地址变换
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);
h:host n:network s:short l:long
ntonhs:把short型数据从网络字节序转化为主机字节序
主机字节序:可能为小端序,可能为大端序 由主机决定
网络字节序:统一为大端序
例:
unsigned long host_addr=0x12345678;
unsigned long net_addr=htonl(host_addr);//0x78563412 (说明本机CPU为小端CPU)(Intel和AMD系列的CPU都采用小端序标准)
网络地址的初始化和分配
inet_addr
sockaddr_in中保存地址信息成员为32位整数型,为分配IP地址,需要将IP地址表示为32位整数型数据。
#include<arpa/inet.h>
in_addr_t inet_addr(const char* string);
//成功返回32位大端序整数型值,失败返回INADDR_NONE
例:
char *addr1="1.2.3.4";
char *addr2="1.2.3.256";
unsigned long conv_addr=inet_addr(addr1);//结果:0x4030201
conv_addr=inet_addr(addr2); //结果:INADDR_NONE
inet_aton
在功能上与inet_addr完全相同,将字符串形式IP地址转换为32位网络字节序整数并返回,但该函数利用in_addr结构体,使用频率更高。
#include<arpa/inet.h>
int inet_aton(const char *string,struct in_addr *addr);
//成功返回1(true),失败返回0(false)
例:
char *addr="127.232.124.79";
struct sockaddr_in addr_inet;
if(inet_aton(addr,&addr_inet.sin_addr)//如果转换成功
{
//结果addr_inet.sin_addr.s_addr:0x4f8ce87f
}
inet_ntoa
#include<arpa/inet.h>
char *inet_ntoa(struct in_addr adr);
//成功返回转换的字符串地址值,失败返回-1
例:
struct sockaddr_in addr1;
addr1.sin_addr.s_addr=htol(0x1020304);
char *str_ptr=inet_ntoa(addr1.sin_addr);//结果1.2.3.4
网络地址初始化
套接字创建过程中常见的网络地址信息初始化方法:
struct sockaddr_in addr;
char *serv_ip="211.217.168.13"; //声明IP地址字符串
char *serv_port="9190"; //声明端口号字符串
memset(&addr,0,sizeof(addr)); //结构体变量addr的所有成员初始化为0
addr.sin_family=AF_INET; //指定协议族
addr.sin_addr.s_addr=inet_addr(serv_ip); //基于字符串的IP地址初始化
addr.sin_port=htons(atoio(serv_port)); //基于字符串的端口号初始化
//addr.sin_addr.s_addr可赋值为INADDR_ANY:自动获取运行服务器端的计算机IP地址,不必亲自输入。
//若同一计算机中分配多个IP地址,只要端口号一致,可从不同IP地址接收数据。故服务器端中优先考虑此方式。
//客户端除非带有一部分服务器端功能,否则不会采用。