【前五篇】系列文章传送门:网络协议10-Socket编程(上):实践是检验真理的唯一标准网络协议11-Socket编程(Part2):眼见为实,耳听为虚网络协议12-HTTP协议:常用但不简单的网络协议13-HTTPS协议:加密路上层出不穷的网络协议14-流媒体协议:说起来不容易我爱你??????????????????????????????????????????????????????????????????????????或者说,或者说是小麦。“……来吧,今天我就让你看看什么是种子。”说到种子,你应该知道它们是用来下载资源的。那么下载资源的途径有哪些呢?洪流下载有什么优势?下载电影的两种方式第一种是通过HTTP下载。这样,经历过的人应该都明白,当下载的文件再大一点的时候,下载速度会要人命的。第二种方式是通过FTP(文件传输协议)。FTP使用两个TCP连接来传输文件。控制连接。服务端被动打开FTP常用的21端口,客户端主动发起连接。连接将命令从客户端传递到服务器,并从服务器返回响应。常用命令有:lsit——获取文件目录,reter——获取一个文件,store——保存一个文件;数据连接。每当在客户端和服务器之间传输文件时,都会创建一个数据连接。FTP的工作模式?在FTP的两个TCP连接中,每传输一个文件,都要建立一个新的数据连接。基于这种数据连接,FTP有两种工作模式:主动模式(PORT)和被动模式(PASV)。需要注意的是,这里的主动模式和被动模式是从服务器的角度来看的。工作模式的流程如下:主动模式工作流客户端随机开启一个大于1024的端口N,向服务器的命令端口21发起连接,同时开启端口N+1进行监听,以及向服务器发送“端口N+1”命令;服务端主动从自己的数据端口20连接到客户端指定的数据端口N+1。被动模式工作流客户端打开FTP连接时,会打开任意两个本地端口N(大于1024)和N+1。然后使用N端口连接服务器的21端口,提交PASV命令;服务器收到命令,打开任意端口P(大于1024),返回“227进入被动模式”报文,其中包含服务器为数据传输开放的端口号P。客户端收到报文,获取端口P号,通过N+1端口连接到服务器的P端口进行数据传输。上面提到的HTTP下载和FTP下载,两者都有一个很大的缺点——难以解决单台服务器的带宽压力。因为它们都是采用传统的C/S结构,这种结构会随着客户端的增多而降低下载速度。这在当今的互联网世界显然是不合理的。我们期望实现“下载的人越多,下载速度相同甚至更快”的愿望。后来,一种叫做P2P的创新方式实现了我们的愿望。P2P‖‖‖P2P是点对点的。这种方式的特点是资源不是一开始就集中存储在某些设备上,而是分散存储在多个设备上。这些设备称为对等设备。下载文件时,只要获取到那些已经存在的文件的peer地址,并与这些peer建立点对点的连接,就可以就近下载文件,而无需到中心服务器。下载文件后,您的设备也称为该网络的对等设备,您旁边的那些机器也可能选择从您那里下载文件。这样就解决了上面的C/S结构单机带宽压力问题。如果你用过P2P2软件,比如BitTorrent,你会看到你的网络不仅有下载流量,还有上传流量。也就是说,你加入了这个P2P网络,你就可以从这个网络下载,别人也可以从你那里下载。在这里下载。这样就实现了下载的人越多,下载速度越快的愿望。种子文件(.torent)整个过程是否完美?是的,结果是美好的,但是为了达到这种美好,我们还有很多准备工作要做。例如,我们怎么知道哪些节点有某个文件?这使用了我们通常所说的种子(.torrent)。.torrent文件由Announce(TrackerURL)和文件信息组成。其中,文件信息包含以下内容:信息区:指定种子包含的文件个数、文件大小和目录结构,包括目录名和文件名;名称字段:指定顶级目录的名称;每个段的大小:BitTorrent(BT)协议将一个文件分成许多小段,然后分段下载;段哈希值:将每个段的整个种子和SHA-1哈希值放在一起。下载时,BT客户端首先解析.torrent文件获取Tracker地址,然后连接到Tracker服务器。Tracker服务器响应下载者的请求,将其他下载者(包括发布者)的IP提供给下载者。下载器然后连接到其他下载器。两者根据.torrent文件,将对方已有的块分开,然后交换对方没有的数据。可见下载过程不需要其他服务器的参与,分散了单条线路上的数据流量,减轻了服务器的压力。下载者每得到一个区块,都需要计算下载区块的哈希验证码,并与.torrent文件中的验证码进行比较。如果相同,则说明区块正确,如果不相同,则需要重新下载区块。此条款旨在解决下载内容的准确性问题。从这个过程也可以看出,这个方法特别依赖Tracker。Tracker需要收集所有peer的信息,并将slave信息提供给downloader,以便downloader相互连接和传输数据。虽然下载过程是去中心化的,但是在加入这个P2P网络的时候,需要用到Tracker中央服务器,它用来登记哪些用户在请求哪些资源。所以,这种工作方式有一个缺点。一旦Tracker服务器出现故障或线路被阻塞,BitTorrent工具将无法正常工作。可以完全去中心化吗?答案是肯定的。去中心化网络(DHT)DHT(DistributedHashTable),在这个网络中,每个加入DHT网络的人都负责存储网络中的资源信息和其他成员的联系方式,相当于所有人组成了一个巨大的分布式存储数据库。Kedemlia协议是一个众所周知的DHT协议。让我们基于这个协议来认识这个神奇的DHT网络。当客户端启动BitTorrent下载资源时,客户端扮演两个角色:peer角色:监听一个TCP端口来上传和下载文件。对外显示我这里有某个文件;DHT节点角色:监听一个UDP端口,通过这个角色,表明这个节点加入了一个DHT网络。在DHT网络中,每个DHT节点都有一个ID。ID是一个长字符串。每个DHTNode负责掌握一些“知识”,即文件索引。换句话说,每个节点都需要知道哪些文件存储在哪些节点上。注意这里只需要有这些“知识”即可,不一定是保存这个文件的节点。当然,每个DHTNode不会有全局的“知识”,也就是说,它不知道所有文件保存在哪里,只需要知道一部分。其中一部分是通过哈希算法计算的。节点ID和文件哈希值每个文件可以计算一个哈希值,DHT节点的ID是一个与哈希值长度相同的字符串。对于文件下载,DHT算法规定如果一个文件计算出一个hash值,具有相同hash值的DHTNode负责知道该文件下载到哪里,即使它自己不保存该文件。当然,并不总是这样的巧合。如果能找到完全相同的hash值,则有可能该文件对应的DHTNode已经下线,所以DHT算法也规定:除了相同的DHTNode外,你应该知道文件保存在哪里,ID和这N个哈希值很接近的DHT节点应该也知道。上图就是一个例子。文件1通过hash运算得到与ID匹配的DHT节点为节点C(当然还会有其他的,为了便于理解,先关注节点C),所以节点C负责知道文件1的存储地址,虽然节点C本身不存储文件1。同理,文件2通过哈希计算得到匹配ID为节点E的DHT节点,但是节点D和E的值非常接近,所以节点D也知道。当然,文件2本身不一定在节点D和E中,但我们假设E有一个副本。接下来,一个新的节点Nodenew上线了。如果要下载文件1,则必须先加入DHT网络。如何加入?在这种模式下,种子.torrent文件不再是Tracker的地址,而是一个Node地址列表,所有这些都已经在DHT网络中了。当然,随着时间的推移,很可能有的退出,有的下线。这里我们假设不是所有的都联系不上,总会有一个是可以联系上的。然后,只要Nodenew在种子中找到一个DHTNode,它就加入网络。nodenew不知道如何联系NodeC,因为seed中的Node列表中很可能没有NodeC,不过没关系,它可以问。DHT网络特别像一个社交网络。Nodenew会去它能联系到的Node问,你知道NodeC的联系方式吗?在DHT网络中,每个Node保存一定的联系方式,但肯定没有所有Node的联系方式。通过节点之间的相互通信,交换联系信息,删除联系信息。这与人们的交流方式相同。你有你的朋友圈,他有他的朋友圈。加了微信就互相认识了,但是如果一段时间后不联系,就可能删除友情了。在社交网络中,还有一个著名的六度理论,就是说社交网络中任意两个人的直接距离不超过六度,也就是说,即使你想联系比尔·盖茨,也可以得到通过最多六个人联系。所以,如果NodeNew想联系C节点,就去万能的朋友圈问,要求转发,朋友再问朋友,直到找到C。如果最后没有找到C,而是一个节点靠近C的可以找到,也可以通过C的相邻节点下载文件1。???在节点C上,告诉Nodenew要下载文件1,可以去B、D或F。这里我们假设Nodenew选择节点B,则新节点将与B建立对等连接并开始下载。一旦开始下载,它本地也有文件1,所以Nodenew告诉C和它的相邻节点我也有文件1,我可以加入文件1的所有者列表。上述过程中省略了new,但是根据hash算法,部分文件的hash值必须匹配Nodenew的ID。在DHT网络中,会有节点告诉它,既然你加入了我们的网络,你也有责任知道某些文件的下载地址。好了,分布式下载完成。但是我们在上面的过程中留下了两个细节问题。1)什么是DHT节点ID和文件哈希值?其实我们可以把节点ID理解成一个160bits(20字节)的字符串,文件的hash也是用这样一个字符串。2)所谓ID相似度,到什么程度才算相似?这里我们将讨论两个节点之间的距离的定义和计算。在Kademlia网络中,两个节点之间的距离是一个逻辑距离。假设节点A和节点B的距离为d,则:d=AXORB如上所述,每个节点都有一个哈希ID,这个ID由20个字符和160位组成。这里,我们以一个5位的ID为例。我们假设节点A的ID是01010,节点B的ID是01001,那么:距离d=AXORB=01010XOR00011=01001=9所以,我们说节点A和节点B的逻辑距离是9.回到我们上面的问题,hash值很近,可以理解为距离很近,也就是离这个节点最近的N个节点都需要知道文件保存在哪里。需要注意的是,这个距离不是地理位置,因为在Kademlia网络中,位置不近,ID近。我们可以把这个距离理解为社交距离,也就是朋友圈的距离,或者社交网络的距离。这与你的空间位置关系不大,而与人们的经历有关。DHT网络节点关系的维护就像人一样,虽然我们经常接触的只是少数,但朋友圈一定是远近相近的。DHT网络的朋友圈也是一样,有远有近,按距离分层。假设某个节点的ID是01010,如果一个节点的ID前面都是相同的数字,只有最后一位不停,这样的节点只有一个,就是01011。与基数的异或值节点为00001,即距离为1。那么对于01010,此类节点被归类为第一层节点,即k-buket1。同理,如果节点的ID与基节点,与倒数第二位不同的是,这样的节点只有两个,即01000和01001,分别为00010和00011为基节点,即距离2和3。这样的节点被归类为第二层节点,即k-bucket2。因此,我们可以总结出如下规则:如果一个节点的ID前面的位数相同,但与从下数第i位,这样的节点只有2^(i-1)个,对于原节点,距离基节点的距离范围为[2^(i-1),2^i],这样一个节点被归类为k-bucketi。你会发现差距越大,陌生人就越多。但是朋友圈是放不下的,所以每层只放K个,这个K可以通过参数配置。在DHT网络中寻找好友假设节点A的ID为00110,要寻找B(10000),异或距离为10110,距离范围为[2^4,2^5),也就是说B的ID和A的Bit5开始不同,所以B可能在k-bucket5中。然后,A检查他的k-bucket5中是否有B,如果有,则结束搜索。如果不是,就在k-bucket5中随便找一个C。因为是二进制的,C和B都保存着A的第5位,那么C的ID的第5位一定要和B一样,即它和B的距离小于2^4,相当于把A和B的距离缩短一半以上。接下来,在C的通讯中请求C用同样的搜索方式找到B,如果C找到了B,就告诉A。通信(D和B的距离小于2^3),向A推荐D,A请求D搜索下一步。你可能已经发现Kademlia的查询机制通过半搜索来缩小范围。对于一个节点总数为N的网络,最多只需要log2(N)次查询就可以找到目标。如下图,节点A正在寻找节点B,最坏的搜索情况:图中的过程如下:A和B的每个数字都不一样,所以相差31,找到的朋友CA不幸在中间,与A的距离是31是16,到B的距离是15;C去他的朋友圈搜索,正好找到了D,他和C的距离是8,和B的距离是7;D去朋友圈搜索,正好找到了E,E和D的距离是4,B是3;E在朋友圈找到F,与E的距离为2,与B的距离为1;F在距离1处找到B。节点通信在Kademlia算法中,每个节点下面有4条指令:PING:测试一个节点是否在线。相当于打电话看能不能打通;STORE:向节点要钱存储一条数据;FIND_NODE:根据节点ID查找节点;FIND_VALUE:根据KEY查找一条数据,其实和FIND_NODE很相似。KEY是文件对应的哈希值,找到保存文件的节点。节点更新整个DHT网络会相互通信,维护朋友在朋友圈的状态。每个桶中的节点按最后一次联系时间的倒序排列。也就是说,朋友圈里最近联系的人,往往是最熟悉的;每次执行4条指令中的任何一条,都会触发一次更新;当一个节点联系自己时,检查它是否已经在k-bucket中。也就是说是否已经在朋友圈了。如果是,则将其移动到k-bucket列表的底部,也就是最近的位置(如果刚刚接触过,则放在最前面,方便以后接触更多)。如果不是,则需要考虑是否将新联系人添加到地址簿中。假设地址簿已满,只需PING列表顶部的节点(最旧的节点)即可。如果PING成功,将旧节点移到链表底部,丢弃新节点(老朋友还是要给点善意)。如果PING不同,则删除旧节点,将新节点加入列表(联系不上的老朋友要删除)。通过以上机制,保证了任意一个节点的加入和离开都不会影响整个网络。总结下载文件可以通过HTTP或FTP完成。这两者都是中心化的下载方式,而P2P则转变了思路,采用了去中心化的下载方式;P2P有两种类型。一种是tracker-dependent,即元数据集中,文件数据分散。另一种是基于分布式哈希算法,其中元数据和文件数据都是分散的。参考:维基百科-DHT网络词条;维基百科-Kademlia条目;刘超-网络协议趣谈系列;
