DNS报文结构
这里面的请求流程比较难懂,希望大伙能够自己琢磨一会,我花了2个小时才看明白/(ㄒoㄒ)/~~
例子:当请求www.liangyuanshao.top的时候
1.我这台主机向本地DNS服务器发请求
2.本地DNS服务器请求根域名服务器,根域名服务器返回dns.top的顶级域名服务器地址
3.本地DNS服务器请求dns.top顶级域名服务器,dns.top顶级域名服务器返回dns.liangyuanshao.top权威域名服务器的地址
4.本地DNS服务器请求上面dns.liangyuanshao.top权威域名服务器的地址,它返回服务器主机的ip地址
5.DNS根据服务器把ip地址告诉我这台主机,主机建立和服务器的TCP通信
P2P应用
P2P文件分发:从单一服务器向大量主机分发一个大文件,每个对等方能够重新分发它所有的该文件的任何部分,从而在分发过程中协助该服务器(P2P文件共享协议BitTorrent)
特性:
直接在对等方间传输:所有内容不经过第三方服务器
高度的可扩展能力:利用众多对等方集合中的资源去分发内容
使用客户机/服务器模式:请求的对等方是客户机,被选中的对等方是服务器
P2P自扩展性
分发时间:所有N个对等方得到该文件的副本所需要的时间
自扩展的直接成因:对等方除了是比特的消费者外还是它们的重新分发者
P2P文件分发协议BitTorrent
洪流(torrent):参与一个特定文件分发的所有对等方的集合
追踪器:每个洪流所具有的一个基础设施结点
BitTorrent如何进行文件分发?采用最稀缺优先的技术
针对她没有的块在她的邻居中决定最稀缺的块(邻居中副本数量最少的块),并首先请求那些最稀缺的块
使最稀缺块得到更为迅速的重新分发——(大致地)均衡每个块在洪流中的副本数量。
分布式散列表(DHT)
DHT是一个由广域范围大量结点共同维护的巨大散列表。散列表被分割成不连续的块,每个结点被分配给一个属于自己的散列块,并成为这个散列块的管理者。
环形DHT:每个对等方并不需要保存整个系统所有对等方的信息,每个对等方仅与它的直接后继和直接前任联系
优点: 每个对等方只需要知道两个对等方,即它的直接后继和直接前任。
缺点:为了找到负责的键(在最差的情况下),DHT中的所有个结点将必须绕环转发该报文,平均发送N/2条报文
依据缺点,我们可用增加捷径:DHT能被设计成每个对等方的邻居数量以及每个请求的报文数量均为O(log N),其中N是对等方的数量
除此之外,我们还要关注对等方扰动:在P2P系统中,对等方能够不加警示地到来和离去。因此,当设计一个DHT时,我们也必须关注存在这种对等方扰动时维护DHT的情况
因此:每个对等方要能够联系其第一个和第二个后继
**当某对等方突然离开时DHT如何维护DHT?**找到离开对等方标记的前一个对等方,然后重新指定它的下一个对等方和下下个对等方,重新维护
**当某对等方突然加入时DHT如何维护DHT?**找到对等方标记的前一个对等方即可,然后重新维护
内容定位体系结构
一个对等方如何确定哪个对等方有所需要的内容?
集中式目录
目录服务器(大型服务器或服务器场):提供目录服务,收集可共享的对象,建立集中式的动态数据库(对象名称到IP地址的映射)。
缺点:单点故障,性能瓶颈,侵犯版权,可靠性(文件传输是分散的,但定位内容的过程是高度集中的)
查询洪泛:Gnutella
全分布方式:无中心服务器,通过洪泛查询,找到所需对象,就是广发询问
缺点:扩展性差, “查询报文”在网络中产生很大的流量
覆盖网络
1.向覆盖网络中的每个邻居发送“查询报文”;
2.每个邻居再向邻居转发,使覆盖网络上的每个对等方都能收到该查询
3.如果收到查询的对等方中有被请求对象,沿反向路径回发“查询命中”报文
层次覆盖网络,KaZaA: 查询
每组包括若干个组员,一个组长
组员与其组长有一个TCP连接,将共享内容告诉组长
组长维护一个数据库,该组的共享内容及相关对等方的IP地址。
相关组长之间建立TCP连接
组长追踪其所有子节点上的内容
请求排队:限制并行上载数量
激励优先权:上载文件比下载文件多的用户优先
并行下载:从多个对等方请求并下载同一个文件的不同部分
TCP编程
客户机程序和服务器程序运行时,分别创建一个客户机进程和一个服务器进程,相互之间通过套接字读写数据进行通信
TCP套接字编程
运行在不同机器上的进程彼此通过套接字传递报文来进行通信
客户机和服务器程序之间的交互
建立TCP连接
传送数据
java程序示例:
客户端:
import java.io.*; import java.net.*; class TCPClient { public static void main(String argv[ ]) throws Exception { String sentence; String modifiedSentence; BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in)); Socket ClientSocket = new Socket("hostname", 6789); DataOutputStream outToServer = new DataOutputStream(ClientSocket.getOutputStream()); BufferedReader inFromServer = new BufferedReader(new InputStreamReader(ClientSocket.getInputStream())); sentence = inFromUser.readLine(); outToServer.writeBytes(sentence + '\n'); modifiedSentence = inFromServer.readLine(); System.out.println("FROM Server: " + modifiedSentence); ClientSocket.close(); } }
服务器端:
import java.io.*; import java.net.*; class TCP Server { public static void main(String argv[]) throws Exception { String ClientSentence; String capitalizedSentence; ServerSocket welcomeSocket = new ServerSocket(6789); while(true) { Socket connectionSocket = welcomeSocket.accept(); BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream())); DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream()); ClientSentence = inFromClient.readLine(); capitalizedSentence = ClientSentence.toUpperCase() + '\n'; outToClient.writeBytes(capitalizedSentence); } } }
UDP套接字编程
- 通信进程之间没有初始握手,不需要欢迎套接字
- 没有流与套接字相联系
- 发送主机将信息字节封装生成分组,再发送
- 接收进程解封收到的分组,获得信息字节
java程序示例:
客户端:
import java.io.*; import java.net.*; class UDPSocket { public static void main(String args[]) throws Exception { BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in)); DatagramSocket ClientSocket = new DatagramSocket(); InetAddress IPAddress = InetAddress.getByName("hostname"); byte[ ] sendData = new byte[1024]; byte[ ] receiveData = new byte[1024]; String sentence = inFromUser.readLine(); sendData = sentence.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 9876); ClientSocket.send(sendPacket); DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); ClientSocket.receive(receivePacket); String modifiedSentence = new String(receivePacket.getData()); System.out.println("FROM Server:" + modifiedSentence); ServerSocket.close(); } }
服务器端:
import java.io.*; import java.net.*; class UDPServer { public static void main(String args[]) throws Exception { DatagramSocket ServerSocket = new DatagramSocket(9876); byte[] receiveData = new byte[1024]; byte[] sendData = new byte[1024]; while(true) { DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); ServerSocket.receive(receivePacket); String sentence = new String(receivePacket.getData()); InetAddress IPAddress = receivePacket.getAddress(); int port = receivePacket.getPort(); String capitalizedSentence = sentence.toUpperCase(); sendData = capitalizedSentence.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port); ServerSocket.send(sendPacket); } } }
这一章我们学到的知识整体的思路框架: