计算机网络自顶向下方法第2章-应用层(application-layer).2
2.4 DNS:因特网的目录服务
2.4.1 DNS提供的服务
DNS的定义
- 实体层面看,DNS是一个由分层的DNS服务器实现的分布式数据库
- 协议层面看,DNS是一个使得主机能够查询分布式数据库的应用层协议
- DNS运行在UDP之上,使用53号端口
1)主机名到IP地址映射的转换服务
2)主机别名(host aliasing)
3)提供负载均衡(load distribution)
2.4.2 DNS工作机理概述
DNS是一个在因特网上实现分布式数据库的精彩范例。
1.分布式、层次数据库
DNS服务器是有层次的,它可以分为三种类型:根DNS服务器, 顶级域(Top-Level Domain, TLD )DNS服务器和权威DNS服务器,分别对应下面三个层次(从上至下)
- 根DNS服务器:有400多个根名字服务器遍及全世界,由13个不同的组织管理
- 顶级域DNS服务器:顶级域服务器负责顶级域名,如com,org,net,edu和gov和所有国家的顶级域名如cn,uk,jp (edu 教育机构域名, gov 政府部门域名 , org 非盈利性的组织 ,com 企业域名 )权威DNS服务器:在因特网上具有公共可访问的主机的每个组织机构必须提供公共可访问的DNS记录,这些记录将这些主机的名字映射为IP地址。 由组织机构的权威DNS服务器保存这些DNS记录,组织机构可以选择实现它自己的权威DNS服务器来保持这些记录,或者通过支付费用将这些记录存储在某个服务提供商的DNS服务器中。多数大学和大公司实现和维护它们自己基本的权威DNS服务器。
- 本地DNS服务器:还有另一类比较重要的DNS服务器,叫做本地DNS服务器(local DNS server),它并不在我们上面所说的DNS层次结构中。本地DNS服务器的作用有以下两点:
- 1)主机和本地DNS服务器一般是相邻的,当主机发出DNS请求的时候,该请求会被发往本地DNS服务器,它起着代理的作用,并将该请求转发到DNS服务器层次结构中
- 2)本地DNS服务器可以通过缓存主机名/IP地址,减少对相同主机名的查询而消耗的时间,改善时延和性能
实际上,在DNS服务中, 并不能通过对某个DNS服务器,通过仅仅一次的“请求/响应”就取得主机名/IP地址的查询结果。相反,需要多个不同的DNS服务器之间进行多次交互才能获取最终的查询结果:
2.DNS缓存
因为缓存,除了少数DNS查询以外,根服务器被绕过了。
2.4.3 DNS记录和报文
1.DNS报文
DNS只有两种报文,即查询和回答报文,并且这两种报文有着相同的格式。下图是DNS报文格式:
2.在DNS数据库中插入记录
假设你刚刚创建了一个网络乌托邦(Network Utopia)公司, 要做的第一件事情就是到注册登记机构注册域名(networkutopia.com), 注册的时候,需要向该机构提供你的权威DNS服务器的名字和IP地址,该注册机构将确保将一个NS记录和A记录被插入com顶级域DNS服务器中。
2.5 P2P文件分发
在P2P文件分发中,每个对等方能够向任务其他对等方重新分发它已经收到的该文件的任何部分,从而在分发过程中协助该服务器
1.P2P体系结构的扩展性
扩展性的直接成因是:对等方除了是比特的消费者外还是它们的重新分发者。
2.BitTorrent
BitTorrent是一种用于文件分发的流行P2P协议。每个下载者在下载的同时不断向其他下载者上传已下载的数据。
2.6 视频流和内容分发网
2.6.1 因特网视频
我们也能使用压缩生成相同视频的多个版本,每个版本有不同的质量等级。
2.6.2 HTTP流和DASH
由于HTTP流具有缺陷,不管客户可用的带宽大小,所有客户都接收到的相同编码的视频。这导致了一种新型基于HTTP的流的研发,称为经HTTP的动态适应性流(Dynamic Adaptive Streaming over HTTP,DASH).在DASH中,视频编码为几个不同的版本,其中每个版本具有不同的比特率,对应于不同的质量水平。
2.6.3 内容分发网(Content Distribution Network,CDN)
几乎所有主要的视频流公司都利用内空分发网。CDN通常采用两种不同的服务器安置原则。
- 深入。
- 邀请做客
1.CDN操作
2.集群选择策略。
2.7 套接字编程:生成网络应用
2.7.1 UDP套接字编程
- UDP是无连接的,从一个端系统向另一个端系统发送独立的数据分组,不对交付提供任何保证。
- 如下图所示,使用UDP的两个通信进程之间的交互有以下几个过程:
1.UDPClient.py
客户端代码:
#socket 模块形成了在python中所有网络通信的基础 from socket import * serverName='45.76.204.40' #包含服务器的主机名或IP地址 serverPort=12000 #目标端口号 #使用socket()创建客户套接字。 #第一个参数指示了地址簇:AF_INET指示了底层网络使用了IPv4 #第二个参数,SOCK_DGRAM指示了它是一个UDP套接字(而不是TCP套接字) #特别注意:我们无需指定客户端套接字的端口号,这个工作由操作系统完成 clientSocket=socket(AF_INET,SOCK_DGRAM) message=input('Input lowercase sentence:') #提示用户从键盘输入,并将输入读取到message中 #sendto()为报文message附上目的地址(serverName,serverPort), #并向进程的套接字clientSocket发送结果分组 clientSocket.sendto(message.encode(),(serverName,serverPort)) #来自因特网的分组到达该客户的套接字时,其分组数据放在变量ModifiedMessage中,源地址放置在serverAddress中 #方法recvfrom取长度2048作为输入 ModifiedMessage,serverAddress=clientSocket.recvfrom(2048) print (ModifiedMessage.decode()) clientSocket.close()
2.UDPServer.py
from socket import * serverPort=12000 serverSocket=socket(AF_INET,SOCK_DGRAM) serverSocket.bind(('',serverPort)) #将端口号与服务器的套接字显示绑定在一起 print('The server is ready to receive') #这个while允许服务器无限期地接收来自客户端的分组 while True: message,clientAddress=serverSocket.recvfrom(2048) modifiedMessage=message.upper() serverSocket.sendto(modifiedMessage,clientAddress)
2.7.2 TCP套接字编程
与UDP不同,TCP是一个面向连接的协议。这意味着,在客户端和服务器能够开始互相发送数据之前,它们要先握手和创建一个TCP连接。连接建立之后,当有一方需要给另一方发送数据,它只需经套接字把数据丢个TCP连接,无需再为数据附上目的地地址。
如下图所示,使用TCP的两个通信进程之间的交互有以下几个过程:
1.TCPClient.py
from socket import * serverName='127.0.0.1' #服务器的IP地址或主机名(这里是本地回送地址) serverPort=12000 #第一个参数AF_INET表明底层网络使用IPv4, #第二个参数SOCK_STREAM表明它是一个TCP套接字(而不是UDP) clientSocket=socket(AF_INET,SOCK_STREAM) #connect()执行完后,执行三次握手,并在客户和服务器程序之间创建起一条TCP连接 clientSocket.connect((serverName,serverPort)) sentence=input('Input lowercase sentence:') #进入客户套接字,并通过TCP连接发送数据 #无需附上目的地地址 clientSocket.send(sentence.decode()) #当字符到达套接字时,它们被放在modifiedSentence,其缓存长度为2048 #知道收到回车符才会结束该行 modifiedSentence=clientSocket.recv(2048) print('From Server:',modifiedSentence.encode()) clientSocket.close()
2.TCPServer.py
from socket import * serverPort=12000 #创建一个欢迎套接字serverSocket,将其绑定在serverPort上 serverSocket=socket(AF_INET,SOCK_STREAM) serverSocket.bind(('',serverPort)) #聆听来自客户的连接请求;参数1表示请求连接的最大数 serverSocket.listen(1) print('The server is ready to receive.') while True: #当有客户敲门时,seerverSocket调用accept(), #在服务器中创建一个叫connectionSocket由这个客户专用 connectionSocket,addr=serverSocket.accept() sentence=connectionSocket.recv(2048) capitalizedSentence=sentence.upper() connectionSocket.send(capitalizedSentence) #关闭连接套接字,没有关闭欢迎套接字 connectionSocket.close()
参考:
https://blog.csdn.net/qq_36464448/article/details/80305497
https://blog.csdn.net/qq_36464448/article/details/80302793
https://www.cnblogs.com/hithongming/category/1245180.html