IP中的路由选择

1

​ 网络这个东西是很复杂得,像一张蜘蛛网一样,将每一台通信设备连在一起,在上图中,工作站A想要访问工作站C,有不止一条路可以走,在现实中可能这样的路有非常多,这些路有远有近,有快的有慢得,那么在连接网络时,设备是如何知道哪一条路是最优的呢?通常,通信设备中都会有一个路由表(Routing Table),其实就是一张二维表格,记录着这台设备如果要去某个地方需要线通过哪些设备中转。

​ 下面是我本机(mac系统)中的路由表(只是部分截图),不光是路由器,每个接入网络的设备都会有路由表:

333

​ 上图是一张典型的主机路由表,执行netstate命令,-r选项是列出路由表,-n选项是以数字格式打印出IP地址(默认情况会打印网络名加主机名),本机的路由表大致由7列组成,下面介绍一下每一列的作用:

  • Destination:目标网络地址;
  • Gateway:网关地址,要去目标网络,需要先走这条路;
  • Flags:此条路由记录的标志,可以设置的标志大致有:
    1. U Up,该路由可以被使用;
    2. G Gateway,该路由是到一个网关(路由器),如果没有设置该标志,说明该条路由不是一个网关,是一条直接路由,Gateway列给出的是外出接口的IP地址;
    3. H Host,该路由是到一个主机,即Destination列给出的是一个完整的主机地址,如果没有设置该标志,说明该路由是到一个网络,而Destination列出的是一个网络地址:一个网络号,或者网络号与子网号的组合;
    4. D Dynamically,该路由是由ICMP重定向报文创建的;
    5. M Modified,该路由已被重定向报文修改;
  • Refs:正在使用该路由的活动进程个数,面向连接的协议如TCP在建立连接时需要固定路由,如果我们用Telnet连接10.158.51.78,它的值将增加1;
  • Use:通过该路由发送的分组数;
  • Netif:该记录使用的网络接口;
  • Expire:该记录过期时间。

​ 标志G是非常重要的,因为它区分了直接路由和间接路由(对于直接路由来说没有标志G)。间接和直接路由的区别在于,发往直接路由的分组中不但具有指明目的端的IP地址,还具有链路层地址,可以理解为数据报中的目的IP地址和链路层目的地址是一样的。当分组被发往一个间接路由时,IP地址指明的是最终的目的地,但是链路层地址指明的是网关(即下一站路由器),可以理解为可以理解为数据报中的目的IP地址和链路层目的地址是不一样的。

​ 标志G和H之间的区别:都代表通行设备,不过功能不一样,G标志区分了直接路由和间接路由,而H标志表明目的地址是一个完整的主机地址。若没有设置H标志,则说明目的地只是一个网络地址(主机号部分为0)。当为某个目的IP地址搜索路由表时,主机地址项必须与目的地址完全匹配,而网络地址项只需要匹配目的地址的网络号和子网号。

路由算法

静态路由选择策略

​ 静态路由选择策略即非自适应路由选择,只在交换机启动时计算和交换路由,此后路由不再改变。特点是简单并且开销较小,但不能及时适应网络状态的变化。具体可以分为以下三种:

  1. 扩散式路由选择

    一个网络节点从A线路收到分组后,立即把分组发向除A线路外的所有其他输出线路上,任何节点只接受最先到达的报文分组,不接受重复报文。适用于规模较小,对可靠性、健壮性要求很高的场合,还可被用于分发信息、判断可达性、寻找最短路径等。

  2. 固定路由选择

    所有网络节点都保存一张路由表,路由表中记录着所有为了到达某个目的节点而选择的下一个节点或链路,并不记录到该目的节点的所有中间节点。所以当一个分组到达节点时,只需要在查找这个路由表查找到对应的下一个节点,并发送分组。因为所有的路由都保存在一张表中,所以很简单,适合于一个负载稳定拓扑变化不大的网络中运行,但灵活度很差,无法对网络的拥塞和故障做出及时地反映。

  3. 随即路由选择

    当分组到达某节点后,随意选择一条线路进行分组转发。随即选择的路由不一定是最佳路由,增加了不必要的负载,而且分组传播延迟不可预期。

动态路由选择策略

​ 动态路由选择策略即自适应路由选择,在交换机启动时进行初始化,当网络发生阻塞或故障时能够随时进行更新。

  1. 孤立路由选择

    每个节点并不利用其他节点来的网络信息,仅根据本节点看到的信息来确定路由。最短等待法,将具有最短队列的链路作为最好路由你想学习算法(backward learning),将逆向的路由节点数最少的链路作为最好路由。

  2. 集中路由选择

    和固定路由选择一样,所有节点都保存一张路由表,和固定路由的区别在于固定路由算法中路由表的建立是手工完成的,而集中路由选择中路由表的建立是由网络中设置的一个路由控制中心RCC来几种完成的(收集、计算、分发)。缺点:离RCC较近的地方通信量的开销比较大,因为要周期性地从所有节点手机网络的状态信息的报告,同时还要生成路由表并从RCC发送到网内的所有节点;另一个是可靠性问题,一旦RCC出现故障,则整个网络就失去控制。

  3. 分布路由选择

    根据来自于相邻节点的信息,并通过一个最短花费路由算法计算出到每个目的地的路由。

动态路由选择中常用的两种算法:

  1. 距离向量路由协议(Distance Vector Routing,DVR)

  2. 链路状态路由协议(Link State Routing)

​ 路由选择是个非常复杂的问题,它既要 网络中所有节点协同工作,也需要路由选择适应环境的不断变化,并且这种变化是事先无法知道的,比如节点故障、网络拥塞等。

参考:《TCP/IP详解 卷1:协议》

对一台新服务器的简单的配置

虽然不是专业的系统管理员,作为程序员还是会经常折腾一些VPS,势必要学会怎么配置一台服务器,而且,对于公司面试,掌握基本的系统管理知识还是有利的。况且,如今的网络安全环境下,掌握一些服务器安全方面的配置是非常有必要的。

1. 远程登录用户

在使用SSH远程登录时,由于root用户有着无限的权利,它能执行任何命令,所以尽量不要使用root用户登录。

Ubuntu
1
2
adduser jack  //创建非根用户
usermod -a -G sudo jack // 让jack用户拥有sudo权限(即通过密码认证后可以执行特殊的权限的命令)
CentOS
1
2
3
adduser jack
passwd jack // 为jack用户设置密码
usermod -a -G wheel jack // 把jack加入wheel用户组

2. SSH密钥对认证

上面创建完jack用户后,就可以执行下面的命令登录:

1
ssh [email protected]

此时,会要求你输入jack的密码,但密码认证也有漏洞,而且会受到暴力破解,不怀好意的人会不断尝试猜测你的密码,而且,每次登录时都要求你输入密码,是不是很麻烦呢?这时我们就需要创建SSH密码对认证(所谓密钥对,就是一对“密钥”,其中一个是私钥,保存在自己的电脑中,另一个是公钥,保存在服务器中,公钥加密的消息只能使用对应的私钥解密)。

1
ssh-keygen  // 创建密钥对

然后按照屏幕提示输入所需要的信息,这个命令会在电脑创建两个文件:~/.ssh/id_rsa.pub(公钥)~/.ssh/id.rsa(私钥),私钥应该保存在本地电脑中,公钥上传到服务器。

1
2
// 把公钥上传到服务器中jack用户的家目录,后面一定要有":"
scp ~/.ssh/id_rsa.pub [email protected]:

登录服务器,创建.ssh目录:

1
mkdir ~/.ssh

创建~/.ssh/authorized_keys文件,这个文件的内容是一系列允许登录这台服务器的公钥:

1
touch ~/.ssh/authorized_keys

把上传的公钥添加到~/.ssh/authorized_keys文件中:

1
cat ~/id_rsa.pub >> ~/.ssh/authorized_keys

最后修改下面几个目录和文件的访问权限,让jack用户访问~/.ssh目录和~/.ssh/ahthorized_keys文件:

1
2
3
chown -R jack:jack ~/.ssh
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

禁用密码和根用户登录

为了让服务器再安全一些,我们要禁止用户通过密码登录,还要禁止根用户登录。

1
vim /etc/ssh/sshd_config

上打开的配置文件中,这样修改:

1
2
3
// /etc/ssh/sshd_config
PasswordAuthentication no // 或者注释掉
PermitRootLogin no // 或者注释掉

顺便解决下ssh自动断开的问题:

1
2
3
// /etc/ssh/sshd_config
ClientAliveInterval 30 # 表示每30秒服务器向客户端发起一次心跳,如果客户端响应就保持连接
ClientAliveCountMax 5 # 如果连续5服务器收不到心跳,就断开连接

改动之后,重启ssh服务:

1
2
3
4
5
# ubuntu
sudo service ssh restart

# CentOS
sudo systemctl restart sshd.service

运行完上面的命令,我们的服务器就安全很多了。


欢迎阅读本篇文章,如有兴趣可以关注博主公众号哦:

用厄拉多塞法筛选素数

最近在看SICP,这本书写的确实不错。3.5节中讲到了无穷流对素数的一个应用:用厄拉多塞筛法来构造出素数的无穷流。这个筛选思路值得记录一下。

厄拉多塞是公元前3世纪希腊亚历山大的哲学家。他由于第一个给出了地球的圆周的精确估计而闻名。他的计算方式是观察夏至日正午影子的角度。虽然厄拉多塞筛法历史如此悠久,但仍成为专用硬件“筛”的基础,直至最近都一直是确定大素数存在的有力工具。直到20世纪70年代,这种算法被概率算法超越。

思路

(前面关于流和无穷流的定义以及说明直接略过了,感兴趣的可以自己看)首先,这个无穷流从整数2开始,因为这是第一个素数。为了得到其余的素数,就需要从2后面的整数中过滤掉所有2的倍数,这样就留下一个从3开始的无穷流,而3也就是下一个素数。现在再从这个流的后面部分过滤掉所有3的倍数,这样就留下一个从5开头的无穷流,而5又是下一个素数,就这样继续下去。换句话说,这种方法就是通过一个筛选过程构造出各个素数。

筛选过程描述如下

对流S做筛选就是形成一个流,其中的第一个元素就是S的第一个元素,得到其随后的元素的方式是从S的其余元素中过滤掉所有S的第一个元素的倍数,而后再对得到的结果进行同样的筛选。

代码

1
2
3
4
5
6
7
8
9
(define (sieve stream)
(cons-stream
(stream-car stream)
(sieve (stream-filter
(lambda (x)
(not (divisible? x (stream-car stream))))
(stream-car stream)))))

(define primes (sieve (integers-starting-from 2)))

上面的Lisp代码写得还是很精练的,没有任何多余的代码。

1574

我们可以将上面的厄拉多塞筛法看作是一个信号处理系统。出入流溃入“反cons”,分解出这个流的首元素和其余元素,用这个首元素去构造一个可除性过滤取,让该流的其余部分穿过这个过滤器,这个过滤器的输出再溃入到另一个筛块,而后将原来的首元素cons到这个内部筛的输出上,形成最终的输出流。这样,不仅输入流是无穷的,信息处理器也是无穷的。

听了这么多年的播客,终于也做了一回嘉宾

1

2017年10月31日,星期二,下午2点,如约接到了国内某容器云公司的电话面试。

电话是从北京打过来的(我是在南京),刚接到电话,我深吸了一口气,安慰自己要放松,之后按下了接通键。

首先,跟面试官简单介绍了一下自己,然后又问我以前做过什么东西没有,我回答道,之前跟着老师做过项目,也和同学接过私活做过。(刚开始的时候,有点紧张,并且还有点害羞😳,语速也有点快)

接着,又让我具体说一下自己参加过的某一个项目,我就开始介绍我去年和同学做的银团的项目,之后,后面的一系列技术相关的问题就开始了

Read More

CSS3中的box-sizing属性

1

box-sizing属性是css3中新添加的属性,用来替换原来的css盒子模型,box-sizing属性值的不同,元素的高度和宽度的计算方法也不同。

1
2
3
4
/* box-sizing的三个属性值,我们只针对前两个说明 */
box-sizing: content-box;
box-sizing: border-box;
box-sizing: padding-box;

在默认情况下,设置的widthheight属性都是指元素内容(content box)的高度和宽度,如果这个元素设置了borderpadding的话,那么整个元素的高度和宽度就是:

1
2
totalWidth = border-left + padding-left + width + padding-right + border-right
totalHeight = border-top + padding-top + height + padding-bottom + border-bottom

所以,这个在做相应式设计的时候还是比较复杂的,现在,有了box-sizing属性,就可以根据不同的属性值计算元素的高度和宽度。

  • content-box:这是默认情况,根据这个属性值的名字也能大概猜出会是什么情况,整个元素的高度和宽度其实就是上面的两个公式
  • border-box:这种情况下,你设置的widthheight属性值就是针对整个元素,包括了border,padding,和元素内容。

简单的例子

CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
.box {
width: 150px;
height: 150px;
padding: 50px;
border: 5px solid blue;
background-color: orange;
}
.box1 {
box-sizing: content-box;
}
.box2 {
box-sizing: border-box;
}
HTML
1
2
3
4
5
6
<div class="box box1">
content-box
</div>
<div class="box box2">
border-box
</div>

代码中,我们对两个div设置了相同的height、width、border和padding,可是现实效果却完全不同:

4771

我们仔细分析下,两个div不同的地方在于box-sizing属性,第一个是content-box,第二个是border-box,针对第一个div,

4986

5118

我们发现,整个元素的高度和宽度是260x260,而元素的内容的高度和宽度是150x150,正好是我们想要的,对于260这个大小是怎么来的,我们不妨计算一下:

1
2
5+50+150+50+5=260  // 高度
5+50+150+50+5=260 // 宽度

正好是260,符合最上面的两个公式,所以最后元素的尺寸是260x260,并不是我们设置的150x150

对于第二个div:

6090

6223

很明显可以看到,第二个div里面的内容已经被挤了换行了,这个div的真实的高度和宽度和我们设置的一样,可以它的内容部分的尺寸只有40x40,远小于150,可以看到,这就是content-boxborder-box的区别了,再来计算一下:

1
2
150 = 5+50+40+50+5 // 高度
150 = 5+50+40+50+5 // 宽度

可知,整个元素的高度其实是包括了border、padding和内容的高度,宽度也是如此。

浏览器的兼容性

  • 桌面端
    7243

  • 手机端
    7383

可以看到,不管是手机端还是桌面端大部分都是不支持padding-box的,所以建议实际开发中避免使用padding-box

跟多详细内容请参考:https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing


欢迎阅读本篇文章,如有兴趣可以关注博主公众号哦: