应用程序体系结构:
(1)客户-服务器体系结构:有一个总是打开的主机称为服务器,服务于其他称为客户的主机的请求。
(2)P2P体系结构:应用程序在间断连接的主机对之间使用直接通信。自扩展性,每个主机可以向其他对等方分发文件为系统增加服务能力。
进程通过套接字的软件接口发送和接收报文。套接字可以看做同一主机内应用层和运输层的接口。
为了标识接收进程,需要定义两种信息:主机的地址(IP地址);目标主机接收进程的标识符(端口号)
可供应用程序使用的运输服务:可靠数据传输、吞吐量、定时、安全性
应用层协议定义了运行在不同端系统上的应用程序进程如何相互传递报文,定义了:交换的报文类型、各种报文类型的语法、字段的语义、一个进程何时以及如何发送报文。
2.1 HTTP概况
Web的应用层协议为超文本传输协议(HTTP),由两个程序实现:客户程序和服务器程序。
Web页面由对象组成,一个对象可以为文件、图形、小程序等,通过URL地址寻址。多数Web页面有一个HTML基本文件以及几个引用对象。HTML基本文件通过对象的URL地址引用页面中的其他对象。URL地址分为两部分:存放对象的服务器主机名和对象的路径名。例如:URL地址http://www.someSchool.edu/someDepartment/picture.gif中www.someSchool.edu为主机名,后面为路径名。
HTTP定义了Web客户向Web服务器请求页面的方式,以及服务器向客户传送页面的方式。
2.2 非持续连接和持续连接
(1)非持续连接:在客户和服务器长时间范围内通信时,每个请求/响应对经单独的TCP连接发送
每个TCP连接只传输一个请求报文和一个响应报文。因此一次请求Web页面往往要产生多个TCP连接。
缺点:必须为每个请求的对象建立和维护一个全新的连接;每个对象要经受两倍RTT的交付时延,一个RTT用于创建TCP,一个传输。
(2)持续连接:所有请求/响应对经相同的TCP连接发送。HTTP默认使用持续连接。
2.3 HTTP报文格式
HTTP请求报文:实体主体在方法为post等才有用,用于关键字搜索等。但GET方法可以将用户的输入放在URL中实现关键字检索。例如https://www.baidu.com/s?wd=计算机网络自顶向下方法。
例如:
GET /somedir/page.html HTTP/1.1 请求行:方法字段(GET、POST、HEAD、PUT、DELETE)、URL字段、HTTP版本字段
Host: www.someschool.edu 首部行:表明对象所在主机
Connection:close 首部行:表明希望服务器发完一个报文断开TCP
HTTP响应报文:
状态码有:200 OK(请求成功);301 Moved Permanently(请求的对象已被转移,新的URL在Location首部行中);400 Bad Request(该请求不能被服务器理解);404 Not Found(请求的文档不在服务器上);505 HTTP Version Not Supported。
例如:
HTTP/1.1 200 OK 状态行:协议版本字段、状态码和相应状态信息
Connection:close 首部号:
Date:Tue,0.9 Aug 2011 15:44:04 GMT 首部号:发送时间
2.4 用户与服务器交互:cookie
HTTP服务器是无状态的,即不标识用户。但如果一个web站点希望可以识别用户,HTTP通过cookie实现。
cookie技术组件:(1)HTTP响应报文中的cookie首部行(2)HTTP请求报文中的cookie首部行(3)用户端系统中保留一个cookie文件,由用户浏览器进行管理(4)位于Web站点的一个后端数据库。
从而服务端可以通过cookie跟踪用户,然后进行推荐等操作。
2.5 Web缓存
web缓存器是能够代表初始Web服务器来满足HTTP请求的网络实体。有自己的磁盘存储空间,并在存储空间中保存最近请求过的对象的副本。
假设浏览器请求对象http://www.someschool.edu/campus.gif,会发生如下情况:
(1)浏览器建立一个到web缓存器的TCP连接,并向web缓存器中的对象发送一个HTTP请求
(2)缓存器进行检查,如果有该对象副本则通过HTTP响应报文回传。若没有该对象,就向初始服务器(www.someschool.edu)请求该对象。
(3)缓存器收到初始服务器的HTTP响应报文后,在本地存储空间存储一份副本,然后向客户的浏览器回传该副本。
Web缓存器的优势:可以大大减少对客户请求的响应时间;可以减小因特网上的web流量,从而改善所有应用的性能。
2.6 条件GET方法
web缓存器存在一个问题:保存在该缓存器中的副本可能是陈旧的。可以通过条件GET方法来证实缓存器的副本是最新的。
条件GET方法:(1)使用get方法(2)请求报文中包含If-Modified-Since: ,代表上次修改的日期。通过最后修改日期来区分是否为最新的内容。
FTP和HTTP都是文本传输协议,但也有一些重要的区别:(1)FTP使用两个并行的TCP连接来传输文件,一个是控制连接,一个是数据连接。控制连接用于两主机间传输控制信息,如用户标识、口令等。数据连接用于发送文件。因此FTP使用两个端口:20和21端口。
当用户主机与远程主机开始一个FTP会话时,FTP的客户端首先在服务器21端口与服务器发起控制TCP连接,并发送用户标识等信息。当服务端从控制连接上收到文件传输命令后,就发起TCP数据连接,传输完毕后关闭。在同一会话中,若客户端来需要传输数据,则打开新的数据连接。因此FTP的控制连接会贯穿整个用户会话,数据链接只在文件传输时建立。
FTP服务器必须在整个会话期间保留用户状态,需要追踪用户在远程目录树上的位置,从而限制了FTP维持的会话总数。
FTP命令和回答:
USER username:用户标识 PASS password:用户口令 LIST:用于向服务器请求所有文件列表,通过数据连接传送
RETR filename:从服务器get文件 STOR filename:向服务器put文件
因特网电子邮件系统组成:用户代理、邮件服务器、简单邮件传输协议(SMTP)。
4.1 SMTP
SMTP用于从发送方的邮件服务器发送报文到接收方的邮件服务器。TCP连接
与HTTP的比较:HTTP是一个拉协议,主要从服务器拉取信息,FTP是推协议。SMTP要求每个报文使用7比特ASCII码格式,对于图像文件等需要转换。SMTP将文本和图形等文件放在一个报文中,而HTTP每个对象放在不同报文中。
4.2 邮件报文格式
每个首部必须含有一个From:首部行和一个To:首部行;也许有Subject:首部行以及其他可选的首部行。
4.3 邮件访问协议
假设A向B发邮件,邮件访问协议将B邮件服务器上的报文传送给B的主机。包括第三版邮局协议(POP3)、因特网邮件访问协议(IMAP)以及HTTP。而SMTP是将邮件从A的用户代理传输到B的邮件服务器。
POP3:比较简单的邮件范文协议。按三个阶段工作:特许、事物处理以及更新。第一阶段通过用户名和口令鉴别用户;第二阶段用户取回报文等操作;第三阶段退出,邮件服务器会删除那些被标记为删除的报文。
IMAP:POP3协议只在本地维持邮件的文件夹,不提供任何创建远程文件夹并为报文指派文件夹的方法。而IMAP服务器把每个报文与一个文件夹联系起来,为用户提供创建文件夹以及将邮件从一个文件夹移动到另一个文件夹的命令,允许用户代理获取报文组件的命令。
HTTP:当你使用浏览器收发邮件时,从用户到邮件服务器之间用HTTP传输。
主机的一种标识方法是用其主机名,例如:cnn.com、www.yahoo.com等。然而该主机名很难被机器辨识,因此用IP地址来标识。
5.1 DNS提供的服务(53号端口)
域名系统(DNS)是将主机名转换为IP地址的目录服务。DNS是:(1)一个由分层的DNS服务器实现的分布式数据库(2)一个使得主机能够查询分布式数据库的应用层协议。
DNS通常由其他应用层协议所使用,假如浏览器要访问URL www.someschool.edu/index.html,做法如下:用户主机上运行着DNS应用的客户端;浏览器将URL中抽取出主机名www.someschool.edu,并将这台主机名传给DNS应用的客户端;DNS客户向DNS服务器发送一个包含主机名的请求;DNS客户最终会收到一个回答报文,并得到主机名的IP地址;浏览器向该IP地址80端口的HTTP服务器进程发起一个请求。
DNS提供的其他服务:
主机别名:有着复杂主机名的主机能拥有一个或者多个别名。
邮件服务器别名:便于记忆的电子邮件别名。
负载分配:DNS可以用于冗余服务器之间进行负载分配。单个站点会有多台服务器,DNS数据中心会存储这些IP地址集合,因此多个服务器可以有相同的别名。
5.2 DNS工作机理
DNS采用分布式的设计方案。
(1)分布式、层次数据库
DNS使用大量DNS服务器,以层次方式组织,分为3中类型:根DNS服务器、顶级域(TLD)DNS服务器、权威DNS服务器。
根DNS服务器:全球一共13个根DNS服务器。规定了合法域名.com .net .org等
顶级域服务器:负责维护顶级域名如com、org以及所有国家顶级域名cn、uk等
权威DNS服务器:在因特网上具有公共可访问主机(web服务器)的每个组织机构必须提供公共可访问的DNS记录,这些记录将这些主机名映射为IP地址。多数大学和大公司都实现或维护其权威DNS服务器。
本地DNS服务器:严格来说并不属于DNS服务器的层次结构,每个ISP都有一台本地DNS服务器。
以访问www.amazon.com为例,客户首先本地服务器联系,本地服务器会与根服务器联系,将返回顶级域名com的TLD服务器的IP地址。然后本地服务器与这些TLD服务器之一联系,将为amazon.com返回权威服务器的IP地址。然后,本地服务器与权威服务器联系,它为www.amazon.com返回IP地址。最后,本地服务器将该IP返回给客户。注意到该过程有4份查询报文和4份回答报文,可以通过DNS缓存解决。
(2)DNS缓存
为了改善时延性能并减少在因特网上传输的DNS报文数量,DNS使用缓存技术。通常在本地服务器实现,可以缓存主机名/IP地址对,可以缓存TLD服务器地址,从而绕过根DNS服务器。
5.3 DNS记录和报文
资源记录是一个4元组:(Name,Value,Type,TTL)
TTL为该记录的生存时间,决定了资源记录应当从缓存中删除的时间。
Type=A,则Name是主机名,Value是该主机名对应的IP地址。
Type=NS,则Name是域,Value是如何获取该域中主机IP地址的权威DNS服务器的主机名。
Type=CNAME,则Value是别名为Name的主机对应的规范主机名。
Type=MX,则Value是别名为Name的邮件服务器对应的规范主机名。从而使得同一公司的邮件服务器和web服务器可以使用相同别名。
UDP套接字编程:
功能:客户从键盘读入一行字符,发给服务端,服务端将其转成大写返回给客户端
UDPClient.py
from socket import *
serverName = "127.0.0.1"
serverPort = 10021
clientSocket = socket(AF_INET,SOCK_DGRAM)
while True:
message = raw_input('Input lowercase sentence:')
if message=='quit':
break
clientSocket.sendto(message,(serverName,serverPort))
modifiedMessage,serverAddress = clientSocket.recvfrom(2048)
print modifiedMessage
clientSocket.close()
AF_INET表示底层为IPv4,SOCK_DGRAM表示其为UDP套接字
UDPServer.py
from socket import *
serverName = "127.0.0.1"
serverPort = 10021
serverSocket = socket(AF_INET,SOCK_DGRAM)
serverSocket.bind((serverName,serverPort))
print ("The server is ready to receive")
while True:
message,clientAddress = serverSocket.recvfrom(2048)
modifiedMessage = message.upper()
serverSocket.sendto(modifiedMessage,clientAddress)
TCP套接字编程:
TCPClient.py
from socket import *
serverName = "127.0.0.1"
serverPort = 10021
clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.connect((serverName,serverPort))
while True:
message = raw_input('Input lowercase sentence:')
if message=='quit':
break
clientSocket.send(message)
modifiedMessage,serverAddress = clientSocket.recvfrom(2048)
print modifiedMessage
clientSocket.close()
TCPServer.py
from socket import *
serverName = "127.0.0.1"
serverPort = 10021
serverSocket = socket(AF_INET,SOCK_STREAM)
serverSocket.bind((serverName,serverPort))
serverSocket.listen(1)
print ("The server is ready to receive")
while True:
connectionSocket,addr = serverSocket.accept()
message = connectionSocket.recv(2048)
modifiedMessage = message.upper()
connectionSocket.send(modifiedMessage)
connectionSocket.close()