C++11 enum新特性

March 11, 2015 at 2:55 pm

在C++11以前的C++版本中,enum和C语言中是没有区别的。enum量是一个全局的整型量,比如像下面这样的代码是无法通过编译的。 // this code won't compile! enum Color {RED, GREEN, BLUE}; enum Feelings {EXCITED, MOODY, BLUE}; Color中的BLUE和Feelings中的BLUE会被当成同一个量。另外一方面,由于仅仅是整型的,所以Color中的GREEN可以和Feeling中的MOODY相比较。 C++11引入了一种强类型枚举,成为枚举类[enum class]。它的语法是在enum后面增加一个class关键字,如下所示。 // […]

IPv6入门(二):来看看IPv6的IP地址

March 7, 2015 at 10:23 pm

这里是本系列的第二篇,这一篇里主要就是来看看128位这么多位的地址,究竟能来干什么。这一部分技术性的东西较少,概念性的东西较多。首先会简单介绍一下IPv6地址的表示方法以及各个部分的意义。然后对IPv6地址的三大种类进行介绍,介绍部分可能略显啰嗦,可以视情况跳过。最后介绍一下IPv6中的子网划分(即IPv4地址中的网络部分)以及接口ID的生成(即IPv4中的主机部分)。好了,进入主题吧。 当初设计IPv4的时候,想想2的32次方这么大的数没可能被用掉吧,哪来那么多设备了,于是就是まさか…とは思わなかった(阿,……,万万没想到)句型,最后发现不够用了(1970年设计,1992年发现不够用)。而2的128次方是什么概念呢,是不是又是一次失算呢,嗯,大概是10的38次方的样子,再深入点说的话,就是地球上每平方米可以有10的23次方个地址,这样想想的话,就当前的样子,似乎也是妥妥够了,以后会怎么发展呢,也只能尽请期待了把。 IPv6地址的表示和意义 一个典型的IPv6地址写成冒号分隔的16进制形式,比如2001:0DB8:0000:2F3B:02AA:00FF:FE28:9C5A。还有一个小简化称为zero suppression,就是把冒号分隔的整个部分是0的部分只用1个0表示,leading zeros则省略,比如上面的写成2001:DB8:0:2F3B:02AA:00FF:FE28:9C5A。除了这种省略以外,对于多个0的部分,比如FE80:0:0:0:2AA:FF:FE9A:4CA2,可以使用双冒号(double colon)来进行进一步的压缩,FE80::2AA::FF:FE9A:4CA2。当然,不能同时有两个压缩的部分,否则就不知道压缩的部分究竟有多少个了。搞成这样其实正常人已经看不怎么懂了,即使是程序员看着也吃力,总之IPv6已经不再希望让普通人去理解,而是希望网络能更加智能化吧。 了解了IPv6的基本表示方式后,我们来看这128位到底都有些什么东西。首先,和IPv4一样,IPv6也有前缀[prefix]的概念,并且和IPv4的CIDR表示方法是一致的(关于这部分的内容自行复习IPv4的部分),形如address/prefix-length的形式,比如2001:DB8:2A0:2F3B::/64就是IPv6的一个大小为2的64次方的子网[subnet],而2001:DB8:3F::/48则是一个汇总路由[summarized route]前缀。这里区分子网和汇总路由,因为在IPv6中,子网的前缀长度固定为64个比特,那些比64个比特要小的都是由多个子网合成的汇总路由。IPv6里没有使用子网掩码,仅使用前缀表示。由于通常Ipv6中的前缀长度对于表示子网来说都是64,所以经常不需要写出前缀。 IPv6的地址种类 IPv6地址分成了三大类,单播[unicast],组播[multicast],泛播[anycast]。单从概念上来说,和IPv4中的单播、组播、泛播的概念是一致的。IPv6中没有广播[broadcast]地址的概念,使用组播地址来代替了IPv4中的广播的功能。为了作为日后的参考,下面将会对这三种类型的地址作较为详细地介绍。不感兴趣的话可以粗略看过并直接跳到后面部分,不过还是推荐至少看一下单播地址的部分。 我们首先来介绍一下单播。一个单播地址唯一标识了在它所归属的地址中的单个接口。而所谓所归属的地址,就是指在这个IPv6网络中每个地址都是唯一的,这样一个范围。可能在另一个范围中和这里使用了同样的IPv6地址,那这两个范围就不是同一个归属了。这种一个地址标识唯一接口的方式也就是单播,所有发往这个地址的包都到达这唯一一个接口。要唠叨一句的是接口和节点并不是一回事。一个节点(主机)可以有多个接口,而给这些接口分配的任意一个IPv6地址都可以标识这个节点。单播地址又分成了好几种,global unicast addresses, link-local addresses, unique local addresses, special […]

IPv6入门(一):从NAT以及它的吐槽开始

March 7, 2015 at 7:05 pm

好不容易填完了链路层协议设计的坑,虽然最后的收尾工作被彻底的放弃了。本篇算是“计算机网络”相关内容的一个番外篇,主要是对IPv6以及现行的(2015)和它相关的一些概念的介绍。“算法”部分“线段树”的坑正在整理中,等整理好了一并发生来。 不知道是不是惯例,看过的网络相关的书在讲IPv6之前都是从对NAT的吐槽开始的,等作者吐槽完NAT感觉有点舒适了,才慢慢开始洋洋得意地介绍IPv6的好处。既然如此,本篇也并不打算脱离这个规律,作为开篇,还是不要一上来就扯IPv6为好。 不论是NAT还是IPv6,都是由于IPv4的IP地址不够用这个原因引起的,虽然还有一些奇怪的其它原因,但地址不够无疑是最根本的。一个ISP提供商只有/16个IP(即65536个,可以温习一下IPv4的知识),那么实际可用的65534个。如果顾客的数量超过这个值,就产生问题了。对于那些不常使用网络的顾客还好,总是随机的分配IP,哪个顾客不用了,就回收IP,要用的顾客分发IP,以此来达到一种平衡。但事实是使用IP的人实在太多了,而且越来越多的人依赖于网络不能自拔,所以很多电脑都是长时间开着连着网络,更不要提用来作为服务器的机子了。IP提供商IP地址缺少的问题归根结底是IP地址总数太少的问题,如果IP地址多的用不完,提供商也就不会只有那么几个IP了。最好的方案就是大家都换到IPv6上去,总所周知,IPv6有128位,这个数字是在是太大了,在可预见的未来内应该是用不完把。但是,要全部替换成IPv6是件非常大的工作,需要全部机器上的地址全部重新分配、更新硬件和软件,这是不可能的,所以IPv6只能是以一种慢慢侵蚀慢慢扩大的方式,逐步地替换掉IPv4,IPv6从1990年开始制定,知道现在(2015)也没有大规模的使用,也证实了这一说法。于是在IP地址不够的情况下就有了一个quick fix,就是NAT(Network Address Translation)。 NAT的基本方针是,将一群用户通过LAN连接起来,它们内部使用私有IP地址,诸如192.168.0.1之类,然后他们的私有IP通过一个叫做NAT box的设备转化成同一个公共IP,于是ISP提供商实际上只用提供一个IP就可以对付一大堆用户。下图展示了一个简单的NAT box的示意图。 无论是用户10.0.0.1还是10.0.0.2,它们要发送的包都首先发送给NAT box,交由它改成公共IP,发给Internet。同样,也由他交回来。这里面要解决的唯一一个技术问题是从互联网拿回来的包如何正确传递给主机。对于在远端的Internet端而言,它只知道公共IP 198.60.42.12给它发了一个包,并不知道内部的私有地址细节,所以,它也只能原封不动的按这个地址给发回来。相当于一家人里的某个人以家庭的名义写了一封信出去,对方也只能以家庭的地址寄回来,接着就需要由家庭内部解决是谁写的了。为了实现这一点,NAT box需要对不同的用户发出的包做某种修改,这个修改不影响服务器对包的理解,但是当服务器返回一个包时,由于修改了这个东西,服务器返回时包含了这部分修改的东西,NAT box就可以据此识别出是谁发的包。不幸的是,IP包的结构里仅只有1个比特位是闲置不用的,其它内容都要被接收方利用,所以,实际发生的就是NAT采取的让人吐槽不已的方式。网络层已经没有办法干什么了,反正大部分人也就发发TCP包和UDP包,直接在上层协议中找个东西改改好了。一个非常合适的字段是TCP或者是UDP包中的source port字段,也就是源端口,它表明了服务器端发送信息回到客户端时由哪个程序(或协议)来接收,有过socket编程经验的都知道,如果没有特殊需要,客户端的源端口是不需要自己指定的,只需要指定服务器端的端口即可,客户端的源端口会由协议本身随机分配一个空闲端口。这个对客户端几乎透明,对服务器端仅仅是用来区分对方机器是哪个程序要自己的包的字段,实在是再好不过了,只要能在抵达真正的机器之前改回来,包的传输就不会出现任何问题。于是NAT的工作原理就非常简单了,source port有16位,所以在NAT中可以内建66536(出于前4096个端口都用特殊用处,还要少些)项的表,对于由10.0.0.1发过来的包,可以做如下修改: 10.0.0.1:5544 -> 198.60.42.12:3344,并把原先的IP和端口储存在NAT中。于是服务器端发送回的包的目的IP是198.60.42.12,目的端口是3344,NAT得到这个端口号后,查询自己内部表索引3344的位置,就是记录着10.0.0.1:5544的地方,于是就知道具体要给那个机器了。 于是终于到了吐槽的时刻了。一个比较核心的点是这样实际上就违背了IP设计的初衷。IP地址本意是让世界上所有机器都有唯一的标识,整个协议都是基于此设计的,而使用了NAT之后,一大堆的机器的IP都是192.168.0.1了。第二个槽点是,内部网通过NAT可以访问外部服务器,但是一台外部服务器是无法主动连接内部本地机器的,因为它并不知道内部LAN的分布情况,私有地址什么的,完全不知道。这也破坏了Internet的设计初衷,本意是任意两台机器都可以端对端连接,现在变成单向的了,外部服务器只能被连接不能主动连接内部机器。第三个槽点是NAT把Internet这种面向无连接的网络变成了某种意义上的面向连接的网络。一旦NAT挂掉,内部表数据丢失了,接下来的TCP连接就完全中断了,而如果只是普通的路由器,挂掉重启对TCP连接之后影响不大。第四个槽点是它违背了下层和设计和上层无关的原则。如果TCP有了二代,source […]