应用层
(一)基本概念
1.应用层功能:为用户提供各种应用程序,如浏览器、聊天软件等等
2.网络应用模型
(1)CS模型:客户端-服务器模型
(2)P2P模型:对等层次模型
3.数据流向(单向):数据传输过程,如何从应用层流向传输层的(浏览器应用程序)
(1)用户输入URL
- URL(Uniform Resource Locator):统一资源定位器,俗称网址
- 主要组成:协议 + 域名 + 文件路径,如:http://www.baidu.com/
(2)URL解析:按照URL组成依次解析
(3)生成HTTP请求报文
(4)DNS解析:依据域名获取其IP地址
- 域名:用户可以看懂的字符串,如:www.baidu.com
- IP:计算机能够看懂的字节串,如:192.168.3.89
- 网络号 + 主机号
- 主机号全为0表示整个子网,主机号全为1表示向整个子网“广播”
- 子网掩码:用于区分网络号与主机号,如:255.255.255.0
- 为1表示网络号,为0表示主机号
(5)通过套接字接口向传输层发送HTTP请求报文
- 套接字描述符:用于指定特定应用程序进程之间的套接字,本质为一段缓存空间
- 套接字API:套接字应用程序编程接口
- 套接字:本质为一组数据
- TCP套接字:四元组(源IP + 源端口 + 目标IP + 目标端口)
- UDP套接字:二元组(目标IP + 目标端口)
4.服务器缓存:为了加快访问速度,服务器会将常用数据缓存起来
(二)HTTP协议
1.HTTP:超文本传输协议
2.持续性与非持续性
(1)持续性(HTTP默认):建立连接后,持续发送报文,直到断开连接
(2)非持续性:发送一次报文,建立一次连接
3.请求报文
(1)请求行:URI(请求数据地址)+ Method(方法)+ HTTP版本号
(2)请求头:请求附加信息(状态 + 说明信息等等)
(3)请求数据:当有向服务器发送数据的请求时,用于存放发送数据
4.响应报文
(1)状态行:状态码 + 状态描述
(2)响应头:响应附加信息
(3)响应数据:用户向服务器请求的数据内容
5.无状态:不保存用户状态信息
- cookie:用户状态监控程序
(三)DNS
1.DNS:域名解析系统
2.DNS结构:分布式DSN服务器,多个服务器共同协作
(1)根DNS服务器
(2)顶级域DSN服务器
(3)权威DNS服务器
(4)本地DSN服务器
3.域名查询流程:通过DNS解析器查询,查询流程与浏览器访问服务器相似
(1)浏览器发出查询请求(调用DNS解析器(DNS客户端))
(2)生成DNS报文,基于UDP传输
(3)分布式DNS服务器查询(服务器IP地址一般存放在内存中),返回IP
4.DNS报文
5.DNS服务器查询方式
(1)迭代查询:由本地DNS服务器作为主查询,依次访问根、顶级域、权威DNS服务器
(2)递归查询:依次由各级DNS服务器为主查询,然后逐级返回
(3)一般为混合模式,主机向本地DNS服务器递归查询,然后本地DNS服务器迭代查询
(四)套接字编程
1.套接字编程流程
(1)创建套接字
- 开辟套接字缓存空间,得到套接字描述符
- 套接字生成(四元组/二元组)
(2)套接字连接(TCP面向连接)
- 利用套接字向服务器端发出连接请求
- 服务器段响应连接,双方建立连接
(3)通信阶段
- 客户端发出请求报文,服务器段接收请求报文
- 服务器端发出响应报文,客户端接收响应报文
(4)断开连接
- 客户端发出断开连接请求,服务器段断开连接
2.编程
(1)UDP套接字
- 客户端
# socket API库
from socket import *
def main():
#本地主机测试
# 主机IP
serverName = '127.0.0.1'
# 应用进程端口号
serverPort = 12000
# 创建套接字
clientSocket = socket(AF_INET,SOCK_DGRAM)
message = input('Input lowercasw sentence:')
#数据发送
clientSocket.sendto(message.encode(),(serverName,serverPort))
#接收数据
modifiedMessage, serverAddress = clientSocket.recvfrom(1024)
print(modifiedMessage.decode())
print(serverAddress)
#关闭套接字
clientSocket.close()
if __name__ == '__main__':
main()
- 服务器端
from socket import *
def main():
serverPort = 12000
#创建UDP套接字
serverSocket = socket(AF_INET,SOCK_DGRAM)
#将本地应用进程端口与套接字关联起来
serverSocket.bind(('',serverPort))
print("The server is ready to receive")
#服务器端不断接收请求
while True:
#接收请求报文
message, clientAddress = serverSocket.recvfrom(1024)
modifiedMessage = message.decode().upper()
#发送响应报文
serverSocket.sendto(modifiedMessage.encode(),clientAddress)
print(clientAddress)
if __name__ == '__main__':
main()
(2)TCP套接字
- 客户端
from socket import *
def main():
serverName = '127.0.0.1'
serverPort = 12000
# 创建TCP套接字
clientSocket = socket(AF_INET,SOCK_STREAM)
# 建立连接
clientSocket.connect((serverName,serverPort))
sentence = input('Input lowercase sentence:')
#发送数据
clientSocket.send(sentence.encode())
#接收数据
modifiedSentence = clientSocket.recv(1024)
print('From Server:',modifiedSentence.decode())
# 断开连接
clientSocket.close()
if __name__ == '__main__':
main()
- 服务器端
from socket import *
def main():
serverPort = 12000
# 创建TCP套接字
serverSocket = socket(AF_INET,SOCK_STREAM)
# 服务器端口号与套接字关联起来
serverSocket.bind(('',serverPort))
# 监听客户端发出连接请求
serverSocket.listen(1)
print("The server is ready to receive")
while True:
#连接建立,获得对应连接的套接字
connectionSocket, adder = serverSocket.accept()
#接收请求报文
sentence = connectionSocket.recv(1024)
capitalizeSentence = sentence.decode().upper()
#发出响应报文
connectionSocket.send(capitalizeSentence.encode())
connectionSocket.close()
if __name__ == '__main__':
main()