###sockaddr
结构体
sockaddr
的缺陷:sa_data
把目标地址和端口信息混在一起了
struct sockaddr {
unsigned short sa_family;
char sa_data[14];
};
sa_family
是通信类型,最常用的值是AF_INET
sa_data
14字节,包含套接字中的目标地址和端口信息
###sockaddr_in
结构体
sockaddr_in
结构体解决了sockaddr
的缺陷,把 port 和 addr 分开储存在两个变量中
struct sockaddr_in {
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
struct in_addr {
unsigned long s_addr;
}
unsigned char sin_zero[8];
}
sin_port
和sin_addr
都必须是NBO(一般可视化的数字都是HBO)
sin_zero
初始值应该使用函数bzero()
来全部置零。
一般采用下面语句
struct sockaddr_in cliaddr;
bzero(&cliaddr,sizeof(cliaddr));
###sockaddr_in
结构体变量的基本配置
struct sockaddr_in ina;
bzero(&ina,sizeof(ina));
ina.sin_family=AF_INET;
ina.sin_port=htons(23);
ina.sin_addr.s_addr = inet_addr("132.241.5.10");
###sockaddr
和sockaddr_in
的相互关系
一般先把sockaddr_in
变量赋值后,强制类型转换后传入用sockaddr
做参数的函数
`sockaddr_in`用于 socket 定义和赋值
`sockaddr`用于函数参数
###最典型的源、目的节点 socket 定义
对于源、目的地址和源、目的地址端口,需要建立两个 socket 变量
cliaddr
绑定源地址和源端口
servaddr
用于connect
和sendto
的设定目的地址和目的端口
struct sockaddr_in servaddr,cliaddr;
create_socket(char *server_addr_string,unsigned int server_port)
{
//源 socket 赋值
bzero(&cliaddr,sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
通常 TCP/UDP 协议源地址和端口都是随机的
cliaddr.sin_addr.s_addr = htons(INADDR_ANY);
cliaddr.sin_port = htons(0);
//目的 socket 赋值
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_aton(server_addr_string,&servaddr.sin_addr);
servaddr.sin_port = htons(server_port);
}
####网络字节顺序(Network Byte Order)
结构体的
sin_port
和sin_addr
都必须是NBO
####本机字节顺序(Host Byte Order)
一般可视化的数字都是HBO
###NBO,HBO 二者转换
inet_addr() //将字符串点数格式地址转化成无符号长整型(unsigned long s_addr s_addr)
inet_aton() //将字符串点数格式地址转化成 NBO
inet_ntoa () //将 NBO 地址转化成字符串点数格式
htons() //"Host to Network Short"
htonl() //"Host to Network Long"
ntohs() //"Network to Host Short"
ntohl() //"Network to Host Long"
常用的是
htons()
,inet_addr()
正好对应结构体的端口类型和地址类型
###三种给 socket 赋值地址的方法
inet_aton(server_addr_string,&myaddr.sin_addr);
myaddr.sin_addr.s_addr = inet_addr("132.241.5.10");
INADDR_ANY
转不转 NBO 随便
myaddr.sin_addr.s_addr = htons(INADDR_ANY);
myaddr.sin_addr.s_addr = INADDR_ANY;
###两种给 socket 赋值端口的方法
#define MYPORT 3490
myaddr.sin_port = htons(MYPORT);
0(随机端口)转不转 NBO 随便
myaddr.sin_port = htons(0);
myaddr.sin_port = 0;
htons/l
和ntohs/l
等数字转换都不能用于地址转换,因为地址都是点数格式,所以地址只能采用数字/字符串转换如inet_aton
,inet_ntoa
唯一可以用于地址转换的htons
是针对INADDR_ANY
cliaddr.sin_addr.s_addr = htons(INADDR_ANY)
###inet_addr()
与inet_aton()
的区别
inet_addr
是返回值型struct sockaddr_in ina;
ina.sin_addr.s_addr = inet_addr("132.241.5.10");
inet_aton
是参数指针型struct sockaddr_in ina;
inet_aton("132.241.5.10",&ina.sin_addr);
inet_ntoa
将 NBO 地址转化成字符串点数格式 参数:结构体变量sinaddr
返回值:字符串指针
a1 = inet_ntoa(ina.sin_addr);
printf("address 1: %s\n",a1); //输出 address 1: 132.241.5.10
inet_addr()
的缺陷:必须对-1
做检测处理 因为inet_addr()
的结果是整型,而发生错误时返回-1
。 而ina.sin_addr.s_addr
是unsigned long
型-1
在long short
显示成111111111
,和IP地址255.255.255.255
相符合!会被误认为广播地址!
转自 麦子屋