07_01、网络编程
一、软件开发架构
1、C/S架构
C: client 客户端
S:server 服务端
客户端可以有多个
服务端需要具备的两大特征:
1. 24小时对外提供服务
2. 必须要有一个公网IP地址
2、B/S架构
B: browser 浏览器
S: server 服务端
本质上B/S也是C/S架构
二、OSI七层协议
互联网的本质就是一系列的网络协议,这个协议就叫OSI协议(一系列协议),按照功能不同,分工不同,人为的分层七层。
实际上这个七层是不存在的。没有这七层的概念,只是人为的划分而已。区分出来的目的只是让你明白哪一层是干什么用的。
七层划分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
五层划分为:应用层、传输层、网络层、数据链路层、物理层。
四层划分为:应用层、传输层、网络层、网络接口层。
每层常见的物理设备
1、物理层
物理层功能:主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0
物理层字面意思解释:物理传输、硬件、物理特性。意思是指:要想上网必须要有网线、路由器...完成计算机与计算机之间的通信。
中间的物理链接可以是光缆、电缆、双绞线、无线电波。中间传的是电信号,即010101…这些二进制位。
2、数据链路层
物理层中传输的二进制数,如果知识单纯的发送0和1电信号,没有任何意义。
数据链路层的功能:就是给电信号定义分组,赋予含义
以太网协议
以太网协议(ethernet):电信号分组的统一标准
ethernet规定:一组电信号构成一个数据报,叫做’帧’,每一数据帧分成:报头head和数据data两部分
- head包含:(固定18个字节)
- 发送者/源地址,6个字节
- 接收者/目标地址,6个字节
- 数据类型,6个字节
- data包含:(最短46字节,最长1500字节)
- 数据报的具体内容:head长度+data长度=最短64字节,最长1518字节,超过最大限制就分片发送
Mac地址
head中包含的源和目标地址由来:ethernet规定接入internet的设备都必须具备网卡,发送端和接收端的地址便是指己方和对方网卡的地址,即Mac地址
Mac地址:每块网卡出厂时都被烧制上一个世界唯一的Mac地址,长度为48位2进制,通常由12位16进制数表示(前六位是厂商编号,后六位是流水线号)
广播
同一局域网内,计算机之间通信靠的是广播
计算机把封装好的数据包(head+data),通过广播向外发送,同一局域网内的所有计算机都会接收到这个广播。
计算机收到这个数据包后会解析数据包的发送者是谁,接受者是谁,如果不是自己的Mac地址,即刻丢掉
3、网络层
网络层的功能:引入一套新的地址用来区分不同的广播域/子网,这套地址即网络地址
网络层的由来
有了ethernet、Mac地址、广播的发送方式,理论上世界上的计算机就可以彼此通信了,问题是世界范围的互联网是由 一个个彼此隔离的小的局域网组成的,那么如果所有的通信都采用以太网的广播方式,那么一台机器发送的包全世界都会收到。这个问题就不仅仅是效率低的问题了,更会是一种灾难。
所以必须找出一种方法来区分哪些计算机属于同一广播域,哪些不是,如果是就采用广播的方式发送,如果不是,就采用路由的方式(向不同广播域/子网分发数据包),Mac地址是无法区分的,它只跟厂商有关
IP协议
规定网络地址的协议叫IP协议,它定义的地址称之为IP地址,广泛采用的v4版本即IPv4,它规定网络地址由32位2进制表示
IP协议规定了接入互联网的任何一台计算机都要有有个ip地址,ip地址能够确定世界上任何一台接入互联网的计算机
ip地址:
ipv4:
最小:0.0.0.0
最大:255.255.255.255
本机回环地址:127.0.0.1
ipv6:表示的范围非常大
本机ip地址的查看方式;win + r => cmd => ipconfig
公网IP和内网IP:
公网IP: 是需要购买的
内网IP:192.168开头
广域网,局域网
4、传输层
传输层的由来
网络层的IP帮我们区分子网,以太网层的Mac帮我们找到主机,然后大家使用的都是应用程序,你的电脑上可能同时开启qq,暴风影音,等多个应用程序。
那么我们通过IP和Mac找到了一台特定的主机,如何标识这台主机上的应用程序,答案就是端口,端口即应用程序与网卡关联的编号。
传输层功能
建立端口到端口的通信
端口(port)
范围0-65535,0-1023为系统占用端口,1024-8000 是常用软件使用的端口,以后我们自己开发的软件端口号要使用8000以后的
一个端口在同一时间不能同时使用
有了Mac地址+IP地址+端口,我们就能确定世界上独一无二的一台计算机上的应用程序
常用软件的端口号
应用程序 FTP TFTP TELNET SMTP DNS HTTP SSH MYSQL
熟知端口 21,20 69 23 25 53 80 22 3306
传输层协议 TCP UDP TCP TCP UDP TCP TCP TCP
# http协议的端口号:80
# https协议: http + ssl证书
TCP协议
也叫流式协议, 可靠协议
三次握手和四次挥手
UDP协议
不可靠传输,没有传输通道
应用场景:远程控制软件
TCP协议和UDP协议的优缺点:
TCP:
1. 数据安全可靠
2. 速度慢
UDP:
1. 数据不安全,也不可靠
2. 速度快
5、应用层
http协议的请求头
1.Accept 告诉服务器,客户端支持的数据类型 2.Accept-Encoding 告诉服务器,客户机支持的数据压缩格式。 3.Accept-Language 告诉服务器,客户机的语言环境。 4.Connection:keep-alive 客户机通过这个头告诉服务器,请求完后是关闭还是保持链接。 5.Content-Length 表示请求消息正文的长度。 6.Content-Type 客户机通过这个头告诉服务器,客户端向服务器发送的数据类型。 7.Cookie 客户机通过这个头告诉服务器,可以向服务器带数据。 8.Host 客户机通过这个头告诉服务器,想访问的主机名。 9.Origin 用来说明请求从哪里发起的,包括且仅仅包括协议和域名。 这个参数一般只存在于CORS跨域请求中,可以看到response有对应的header:Access-Control-Allow-Origin。 10.Referer 客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的。(一般用于防盗链) 11.User-Agent 客户机通过这个头告诉服务器,客户机的软件环境。 12.Accept-Charset: 告诉服务器,客户端采用的编码。 13.Date: 客户机通过这个头告诉服务器,客户机当前请求时间。 14.If-Modified-Since 客户机通过这个头告诉服务器,资源的缓存时间。
http协议的响应头
1.Connection 服务器通过这个头,响应完是保持链接还是关闭链接。 2.Content-Encoding 服务器通过这个头,告诉浏览器数据采用的压缩格式。 3.Content-Type 服务器通过这个头,回送数据的类型 4.Date 告诉客户机,返回响应的时间。 5.Server 服务器通过这个头,告诉浏览器服务器的类型 6.Transfer-Encoding HTTP协议头字段Transfer_Encoding,分块传输编码,一般出现在http的响应头中。该头字段存在与HTTP协议的1.1版本中,提供一种数据传输机制。 通常http协议在传输数据时是整体一起发送的,数据体的长度由Content-Length字段指定,方便判断消息结束。 服务器通过这个头,告诉浏览器数据的传送格式。 7.vary Vary 字段用于列出一个响应字段列表,告诉缓存服务器遇到同一个 URL 对应着不同版本文档的情况时,如何缓存和筛选合适的版本。 8.Location 这个头配合302状态码使用,告诉用户端找谁。 9.Content-Length 服务器通过这个头,告诉浏览器回送数据的长度 10.Content-Language 服务器通过这个头,告诉服务器的语言环境 11.Last-Modified 服务器通过这个头,告诉浏览器当前资源的缓存时间 12.Refresh 服务器通过这个头,告诉浏览器隔多长时间刷新一次 13.Content-Disposition 服务器通过这个头,告诉浏览器以下载的方式打开数据。 14.ETag:与缓存相关的头。 (1)Expires 服务器通过这个头,告诉浏览器把回送的数据缓存多长时间。-1或0不缓存。 (2)Cache-Control和Pragma 服务器通过这个头,也可以控制浏览器不缓存数据
三、Socket编程
1、什么是Socket编程
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的
2、套接字工作流程
3、 基于TCP协议的套接字编程(简单)
3.1 服务端
# 1. 实例化对象socket import socket # 2. 得到对象 # 2.1. 如果不传参数,代表的是TCP协议:SOCK_STREAM # 2.2 type=socket.SOCK_DGRAM => UDP协议 # server = socket.socket(type=socket.SOCK_STREAM) server = socket.socket() # 3. 绑定 server.bind(('127.0.0.1', 8002)) # 4. 监听, 数字代表的是半连接池 server.listen(3) print('服务端开始接收客户端消息了:') # 5. # sock: 当前连接的客户端对象 # addr: 客户端的地址 sock, addr = server.accept() # 6. 接收客户段发送的消息 # 1024代表的是字节数,接收数据的最大字节数 # 粘包现象 data = sock.recv(1024) # hello print('客户端数据:', data) # 7. 给客户端返回数据 sock.send(data.upper()) # HELLO # 8. 断开连接 sock.close() # 9. 关门 server.close()
3.2 客户端
# 1. 实例化对象 import socket client = socket.socket() # 2. 连接 client.connect(('127.0.0.1', 8002)) # 3. 给服务端发送数据,发送的数据类型必须是字节类型 client.send('hello'.encode('utf-8')) # 4. 接收服务端发送过来的数据 data = client.recv(1024) print('服务端的数据:', data) # 5. 断开连接 client.close()
4、 基于TCP协议的套接字编程(循环)
4.1 服务端链接循环 + 异常处理
# 1. 实例化对象socket import socket # 2. 得到对象 # 2.1. 如果不传参数,代表的是TCP协议:SOCK_STREAM # 2.2 type=socket.SOCK_DGRAM => UDP协议 # server = socket.socket(type=socket.SOCK_STREAM) server = socket.socket() # 3. 绑定 server.bind(('127.0.0.1', 8002)) # 4. 监听, 数字代表的是半连接池 server.listen(3) print('服务端开始接收客户端消息了:') # 5. # sock: 当前连接的客户端对象 # addr: 客户端的地址 while True: sock, addr = server.accept() # 6. 接收客户段发送的消息 # 1024代表的是字节数,接收数据的最大字节数 # 粘包现象 while True: try: data = sock.recv(1024) # hello if len(data) == 0: continue print('客户端数据:', data) # 7. 给客户端返回数据 sock.send(data.upper()) # HELLO except Exception as e: print(e) break # 8. 断开连接 sock.close() # 9. 关门 server.close() # 暂不考虑关闭服务端
4.2 客户端通信循环
# 1. 实例化对象 import socket client = socket.socket() # 2. 连接 client.connect(('127.0.0.1', 8002)) while True: input_data = input('请输入要发送的数据:') # 3. 给服务端发送数据,发送的数据类型必须是字节类型 client.send(input_data.encode('utf-8')) # 4. 接收服务端发送过来的数据 data = client.recv(1024) print('服务端的数据:', data) # 5. 断开连接 client.close() # 暂不考虑关闭客户端
5.1 服务端
import socket server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 数据报协议-》UDP server.bind(('127.0.0.1', 8080)) while True: data, client_addr = server.recvfrom(1024) print('===>', data, client_addr) server.sendto(data.upper(), client_addr) server.close() # 暂不考虑关闭服务端
5.2 客户端
import socket client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 数据报协议-》UDP while True: msg = input('>>: ').strip() # msg='' client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080)) data, server_addr = client.recvfrom(1024) print(data) client.close() # 暂不考虑关闭客户端
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通