传智扫地僧课程学习笔记。
IPv4套接口地址结构
IPv4套接口地址结构通常也称为“网际套接字地址结构”,它以“sockaddr_in”命名,定义在头文件<netinet/in.h>中
struct sockaddr_in {
uint8_t sin_len; 4
sa_family_t sin_family; 4
in_port_t sin_port; 2
struct in_addr sin_addr; 4
char sin_zero[8]; 8
};
sin_len:整个sockaddr_in结构体的长度,在4.3BSD-Reno版本之前的第一个成员是sin_family.
sin_family:指定该地址家族,在这里必须设为AF_INET
sin_port:端口
sin_addr:IPv4的地址;
sin_zero:暂不使用,一般将其设置为0
通用地址结构
struct sockaddr {
uint8_t sin_len;
sa_family_t sin_family;
char sa_data[14]; //14
};
q sin_len:整个sockaddr结构体的长度
q sin_family:指定该地址家族
sa_data:由sin_family决定它的形式。
关于这两个结构,结论就是,你可以当它们两个一样,
比较关键的细节是,
第一个结构的前2个,与第二个结构的前两个,对应,
第一个结构的后3个,与第二个结构的最后一个对应,即3对1,
旁边标有大小,帮助你计算,
我还得再补一刀,现实中,第一种类型的可能有好几个,但是它们都向第二种通用的靠拢,
/*********************我是可爱的分割线*******************************/
字节序,
大小端的概念,我就不说了,每次都记不清,
主机字节序,也叫本地字节序,不同主机可能不同,
网络字节序,就是大端字节序,
就以这个例子,来记忆大小端,
0x 12 34 56 78 是我们要存储的数据,
----------------------------->> 这个是内存地址的增长方向,从0~XX
如果是12 34 56 78,就是大端字节序,
如果是78 56 34 12,就是大端字节序,
有时候文字理解,不是那么直观,
12345678就是大端字节序,顺~
下面就涉及到由于不同主机通过网络传输数据,引起的大小端转换,
来个题外话,XML就是一种处理的方式,
首先你就得判断,你自己的主机是大端还是小端,
int main()
{
unsigned int data = 0x12345678;
char *p = &data;
printf("%x,%x,%x,%x\n", p[0], p[1], p[2], p[3] );
if( p[0]==0x78)
{
printf("little model\n"); //我想写中文,小端的,可是尼玛我没安装中文,
}
else
{
printf("big model\n");
}
return 0;
}
我的电脑输出为 78,56,34,12
man 3 htonl,得到这些结果,
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
h代表host;n代表network s代表short;l代表long,不过从后面uint32就可以大概看出来,
在上面代码的基础上,加上它,来使用系统提供的大小端转换函数,
uint32_t mynetdata = htonl( data);
p = &mynetdata;
printf("%x,%x,%x,%x\n", p[0], p[1], p[2], p[3] );
转换为网络字节序,输出结果为 12,34, 56, 78
ip地址涉及到两种形式,
一种是我们平常常见的,即 192.168.0.1,另一种是计算机里面的32位bit的形式,
因此就涉及到两种形式的转换,
地址转换函数
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp,struct in_addr *inp);
in_addr_t inet_addr(const char*cp);
char *inet_ntoa(struct in_addr in);这几个函数,我是这样看的,
const代表输出参数,而struct _addr又是我们之前讲到过的ip地址结构体,
第一个函数的返回值,没有猜错的话,就是用来说明函数执行情况的,
char *类型,结合man文档,很容易想到是字符串类型的ip地址表示"192.168.0.1";
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
第二个结构体定义的in_addr被用于第一个结构体中的元素,
int main()
{
char *a = "192.168.6.222";
in_addr_t myint = inet_addr( a);
printf("%u\n", myint);
struct in_addr inp;
inet_aton( "192.168.6.222", &inp);
printf("%u\n", inp.s_addr);
a = inet_ntoa( inp);
printf("%s\n", a);
return 0;
}
输出结果为:
3724978368
3724978368
192.168.6.222,
老师说第三个函数,请深刻理解为什么不传入指针,而是元素,
/* 上面第二个示例代码,
究竟是定义指针,还是直接定义实体?
指针的话,你还得去分配内存,
实体的话,就相当于已经分配了内存,
但是地址得显示引用
*/