早在19年5月就在某站上看到sylar的视频了,一直认为这是一个非常不错的视频。
由于本人一直是自学编程,基础不扎实,也没有任何人的督促,没能坚持下去。
每每想起倍感惋惜,遂提笔再续前缘。
为了能更好的看懂sylar,本套笔记会分两步走,每个系统都会分为两篇博客。
分别是【知识储备篇】和【代码分析篇】
(ps:纯粹做笔记的形式给自己记录下,欢迎大家评论,不足之处请多多赐教)
QQ交流群:957100923
Address模块-知识储备篇
一、IP地址的组成(我们只讲解IPV4了解概念扫盲即可,铺展开来讲篇幅太长)
局域网中只有同网段下的主机才能互相访问!!!
组成:IP地址 = 网络号 + 主机号
网络号:网络号相同表示属于同一个子网
主机号:表示子网中的某台主机
以下是一个IPV4的例子:
进制 | 8位 | 8位 | 8位 | 8位 |
---|---|---|---|---|
十进制 | 192 | 168 | 10 | 1 |
二进制 | 11000000 | 10101000 | 00001010 | 00000001 |
如表所示,由于没有指定网络号和主机号的分界线,所以网段并不明确
如果192.168 是网络号,10.1就是主机号
如果192.168.10是网络号,1就是主机号
所以我们貌似缺少一个东西来指定这个分界线,否则将无法确定网络号!!!
二、子网掩码
作用:用来标识子网,必须与IP同时存在。
1.子网掩码中必须由连续的1和连续的0组成
2.连续的1表示网络地址,连续的0表示主机地址
例如:
IP:192.168.1.1
子网掩码:255.255.255.0 ,
那ip对应的的网络号和主机号是多少?
分析:子网掩码换算成二进制:11111111.11111111.11111111.00000000
结论:子网掩码中连续的1表示网络号,连续的0表示主机号,对应到IP上即:192.168.1表示网络号,1表示主机号
进制 | 8位 | 8位 | 8位 | 8位 |
---|---|---|---|---|
IP十进制 | 192 | 168 | 1 | 1 |
子网掩码十进制 | 255 | 255 | 255 | 0 |
IP二进制 | 11000000 | 10101000 | 00000001 | 00000001 |
子网掩码二进制 | 11111111 | 11111111 | 11111111 | 00000000 |
与运算的结果为 | 11000000 | 10101000 | 00000001 | 00000000 |
结果十进制 | 192 | 168 | 1 | 0 |
大家要是这部分知识一直搞不清楚的话,不妨拿起纸和笔,不要吝啬你的草稿纸。
抛开十进制,用二进制全部理解一遍,再转到十进制。
其实我这边建议:如果有人和我一样,属于不太聪明类型的,可以不用去思考十进制。
只要把二进制表示模式下搞清楚就可以了,十进制只是一种表现形式而已。
三、~0u 什么意思?
#include <iostream>
int main(int argc,char** argv) {
std::cout << "~0 = " << ~0<< std::endl;
std::cout << "~0u = " << ~0u<< std::endl;
return 0;
}
输出结果:
//默认int类型
//0的正码为00000000,因为首位为0所以三码一致,
//按位取反为11111111(此时为按位取反后的补码),
//将补码转换为反码为11111110,
//反码再转换为正码输出(首位不变)为10000001也就是-1
~0 = -1
//无符号整型
~0u = 4294967295 <=> 11111111 11111111 11111111 11111111
四、(1<<31)-1 什么意思?
c++中int占四个字节,也就是32位,其中第一位(最高位)为符号为。
(1<<31)表示1左移31位,使得符号位为1,其他位为0。此时为负数
再将左移后的结果减一就使得符号位为0,其他位都为1,【即为int表示的有符号数的最大整数】。
五、sockaddr、sockaddr_in、sockaddr_in6
/* 通用套接字地址的结构 */
struct sockaddr
{
uint16 sa_family; /* 地址族和长度 */
char sa_data[14]; /* 地址数据 */
};
/* Internet套接字地址的结构 */
struct sockaddr_in
{
uint16 sin_family; /* 地址组族AF_INET*/
uint16 sin_port; /* 端口号 */
uint32 sin_addr.s_addr; /* 网络地址 */
unsigned char sin_zero[8]; /* 填充到“struct sockaddr”的大小 */
};
/* IPv6 套接字地址的结构 */
struct sockaddr_in6
{
uint16 sin6_family; /* 地址组族AF_INET6 */
uint16 sin6_port; /* 端口号 */
uint32 sin6_flowinfo; /* IPv6 flow information */
uint8 sin6_addr[16]; /* 网络地址 */
uint32 sin6_scope_id; /* IPv6作用域id */
};
补充:
uint16 :占2个字节
uint32 :占4个字节
我们发现结构 sockaddr 和 sockaddr_in 字节数完全相同,都是16个字节,所以可以直接强转。
但是结构 sockaddr_in6 有28个字节,为什么在使用的时候也是直接将地址强制转化成(sockaddr*)类型呢?
这几个结构在作为参数时基本上都是以指针的形式传入的
我们拿函数bind()为例,这个函数一共接收三个参数:
第一个为监听的文件描述符。
第二个参数是sockaddr*类型。
第三个参数是传入指针原结的内存大小。
所以有了后两个信息,无所谓原结构怎么变化,因为他们的头都是一样的,也就是uint16 sa_family,那么我们也能根据这个头做处理。
int bind(int socket_fd, sockaddr* p_addr, int add_size);
今天就写到这吧,博客中不明白的可以搜索相关知识进行深入研究,这里点明了要掌握的基础内容。
【最后求关注、点赞、转发】
QQ交流群:957100923