第八周学习笔记总结

总结

设计模式

1.如何理解设计模式
	在IT行业有很多前辈针对固定的一些问题设计出了固定的解决套路
2.设计模式总共有23种
	我们目前不需要掌握这么多种 后续再慢慢看(现在能力不足)
3.设计模式的分类(三类)
	创建型
	结构型
	行为型
4.设计模式之单例模式
	类加括号调用多次只允许产生一个对象
    """正常情况下 类名只要加括号实例化产生对象 执行几次就会产生几个不同的对象"""
  	'''有时候我们不希望类频繁的产生不同的对象
  		类中有很多很好用的方法 程序很多地方都需要使用(通过对象调用)
  		如果产生的地方特别多 那么会浪费一定的内存空间 所以需要使用单例
  	'''

pickle模块

pickle模块与json模块很像 都是用来做序列化 反序列化的
并且pickle模块支持python所有数据类型
但是pickle不支持跨语言传输 只能python自己跟自己玩 兼容性不好 

为了比较方便的编写选课系统 我们需要将对象保存到文件 所以需要用该模块
后续我们不用 因为有更加高级的方法>>>:ORM(对象关系映射)

选课系统项目分析

选课系统
  角色:学校、学员、课程、讲师
  要求:
    1. 创建北京、上海 2 所学校
    2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开
    3. 课程包含,周期,价格,通过学校创建课程
    4. 通过学校创建班级, 班级关联课程、讲师5. 创建学员时,选择学校,关联班级
    5. 创建讲师角色时要关联学校,
    6. 提供三个角色接口
    	6.1 学员视图, 可以注册, 交学费, 选择班级,
    	6.2 讲师视图, 讲师可管理自己的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩   
    	6.3 管理视图,创建讲师, 创建班级,创建课程
    7. 上面的操作产生的数据都通过pickle序列化保存到文件里


功能分析
    管理员功能(最核心)
        1.注册
       2.登录
        3.创建讲师
       4.创建学校
        5.创建课程
    讲师功能
        1.登录
       2.查看教授课程
        3.选择教授课程
       4.查看课程学生
        5.评判学生分数
    学生功能
         1.注册
        2.登录
         3.选择学校
        4.选择课程
         5.查看分数

选课系统目录搭建

三层架构
    功能展示层
    core
        src.py
        admin_view.py
        teacher_view.py
        student_view.py
    核心逻辑层
    interface
        admin_interface.py
        teacher_interface.py
        student_interface.py
    数据处理层
    db
        db_hanlder.py
        models.py

    conf
        settings.py
    lib
        common.py
    start.py
    readme
    requirements.txt

软件开发架构

软件开发架构就是编写项目之前需要遵循的代码层面上的规范(代码运行的流程 环节 步骤)

1.c/s架构
c:client(客户端)
s:server(服务端)
2.b/s架构
b:browser(浏览器)
s:server(服务器)

b/s架构本质也是c/s架构
通过浏览器来充当各个服务端的客户端,用户无需对应下载相应客户端,直接在浏览器上使用功能体验服务

两种架构的优缺点

c/s架构 b/s架构
优点 下载对应的客户端 可以在客户端软件内高度定制相关服务 不需要下载客户端 能够快速体验服务
缺点 使用必须先下载客户端 比较繁琐 定制花里胡哨的功能较为繁琐

架构发展趋势

统一接口原则,c/s架构和b/s架构交错使用,避免各自的劣势

网络编程简介

网络编程就是基于互联网编写代码,程序可以实现远程数据交互

网络编程的本质就是为了解决计算机之间的远程数据交互

计算机之间要想实现远程数据交互 首要条件就是要有物理连接介质

OSI七层协议

规定了计算机涉及到数据远程交互的时候,必须要经过的部件/流程,所有的计算机在

涉及到网络传输这块必须要有相同的零部件

应用层
表示层
会话层
传输层
网络层
数据链路层
物理连接层
ps:记忆小技巧>>>: 应\表\会\传\网\数\物

物理连接层

保证物理连接介质的条件 传递电信号(主要研究插网线情况)

数据链路层

规定了电信号的分组方式

规定了每台计算机都必须有一块网卡,网卡上必须有一串记录>>>:电脑的以太网地址(身份证号) mac地址

网络层: IP协议

规定了任何接入互联网的计算机都必须有一个IP地址(护照)

IPV4:点分十进制

IPV6:十六进制

IP地址可以唯一标识地球上独一无二的一台接入互联网的计算机

传输层: PORT协议

端口协议:规定了一台计算机上的每一个正在运行的应用程序都必须有一个端口号,端口号相当于是计算机用来管理多个应用程序的标记

IP+PORT

IP:用于标识全世界任意一台接入互联网的计算机

PORT:用于标识一台计算机上的某个应用程序

IP+PORT:用于标识全世界任意一台接入互联网的计算机上的某一个具体的程序

应用层

主要取决于程序员自己采用什么策略和协议,常见协议有:HTTP HTTPS FTP...

网络相关设施

交换机

能够让接入交换机的多台计算机实现彼此互联

以太网通信(mac通信)

有了交换机之后 根据电脑的mac地址就可以实现数据交互

局域网

有某个固定区域组成的网络

广域网可以看成是更大区域的局域网

路由器

将多个局域网连接到一起的设备

广播:先在交换机中吼 所有接入交换机的设备都能收到

单播:只有被查找设备 才会回复相应信息

网址(URL):统一资源定位符

TCP与UDP协议

TCP和UDP都属于传输层,规定了数据传输所遵循的规则

ps:数据传输能够遵循的协议有很多 TCP和UDP是较为常见的两个

TCP协议

TCP类似于打电话:你一句我一句 有来有往
三次握手
    建立双向通道
    ps:洪水攻击
      同时让大量的客户端朝服务端发送建立TCP连接的请求
四次挥手
    断开双向通道
    中间的两步不能合并(需要有检查的时间)	
"""
基于TCP传输数据非常的安全 因为有双向通道(描述不够准确)
  基于TCP传输数据,数据不容易丢失!!! 不容易丢失的原因在于二次确认机制
	基于TCP发送的消息会在本地先保存该消息,确认对方收到然后接收反馈信息才会删除,否则在一定的时间内会频繁的多次发送直到对方确认或者超时为止
"""

UDP协议

UDP类似于发短信:只要发送了 不管别人看没看到 也不管回不回复
  是不可靠的、不需要建立双下通道,数据传输效率高,但是可能会丢失
    基于UDP协议发送数据 没有任何的通道也没有任何的限制
	  UDP发送数据没有TCP安全(没有二次确认机制)

socket套接字编程

编写一个cs架构的程序,实现数据交互,需要编写代码操作OSI七层,相当的复杂。由于操作OSI七层是所有cs架构的程序都需要经历的过程,所以有固定的模块。socket套接字是一门技术,socket模块提供了快捷方式,不需要自己处理每一层。

基于文件类型的套接字家族
	套接字家族的名字:AF_UNIX
基于网络类型的套接字家族
	套接字家族的名字:AF_INET

服务端

"""运行程序的时候  肯定是先确保服务端运行 之后才是客户端"""
import socket
# 1.创建一个socket对象
server = socket.socket()  # 括号内什么都不写 默认就是基于网络的TCP套接字
# 2.绑定一个固定的地址(ip\port)
server.bind(('127.0.0.1', 8080))  # 127.0.0.1本地回环地址(只允许自己的机器访问)
# 3.半连接池
server.listen(5)
"""
半连接池---设置的最大等待人数可以节省资源,提高效率
"""
# 4.开业 等待接客
sock, address = server.accept()
print(sock, address)  # sock是双向通道 address是客户端地址
# 5.数据交互
sock.send(b'hello big baby~')  # 朝客户端发送数据
data = sock.recv(1024)  # 接收客户端发送的数据 1024bytes
"""
recv和send接收和发送的都是bytes类型的数据
"""
print(data)
# 6.断开连接
sock.close()  # 断链接
server.close()  # 关机

客户端

import socket
# 1.产生一个socket对象
client = socket.socket()
# 2.连接服务端(拼接服务端的ip和port)
client.connect(('127.0.0.1', 8080))
# 3.数据交互
data = client.recv(1024)  # 接收服务端发送的数据
print(data)
client.send(b'hello sweet server')  # 朝服务端发送数据
# 4.关闭
client.close()

代码优化

1.send与recv
    客户端与服务端不能同时执行同一个
      有一个收 另外一个就是发
      有一个发 另外一个就是收
    不能同时收或者发!!!
2.消息自定义
    input获取用户数据即可(主要编码解码)
3.循环通信
    给数据交互环节添加循环即可
    # 服务端
    while True:
    data = sock.recv(1024)  # 听别人说话
    print(data.decode('utf8'))
    msg = input('请回复消息>>>:').strip()
    sock.send(msg.encode('utf8'))  # 回复别人说的话

    # 客户端
    while True:
    msg = input('请输入你需要发送的消息>>>:').strip()
    client.send(msg.encode('utf8'))  # 给服务端发送消息
    data = client.recv(1024)  # 接收服务端回复的消息
    print(data.decode('utf8'))
4.服务端能够持续提供服务
    不会因为客户端断开连接而报错
      异常捕获 一旦客户端断开连接 服务端结束通信循环 调到连接处等待
    while True:
        try:
            data = sock.recv(1024)  # 听别人说话
            if len(data) == 0:
                break
            print(data.decode('utf8'))
            msg = input('请回复消息>>>:').strip()
            if len(msg) == 0:
                msg = '太忙 暂无消息'
            sock.send(msg.encode('utf8'))  # 回复别人说的话
        except Exception:
            break
'''
 客户端如果异常断开 服务端代码应该重新回到accept等待新的客人
 '''
5.消息不能为空
    判断是否为空 如果是则重新输入(主要针对客户端) 
# 客户端
while True:
    msg = input('请输入你需要发送的消息>>>:').strip()
    # 用户如果什么都不输 直接回车 那么不该往下走
    if len(msg) == 0:
        continue
    client.send(msg.encode('utf8'))  # 给服务端发送消息
# 服务端
msg = input('请回复消息>>>:').strip()
if len(msg) == 0:
    msg = '太忙 暂无消息'
6.服务端频繁重启可能会报端口被占用的错(主要针对mac电脑)
	from socket import SOL_SOCKET,SO_REUSEADDR
	server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
7.客户端异常退出会发送空消息(针对mac linux)
	针对接收的消息加判断处理即可

半连接池

在py文件默认同一时间只能运行一次,如果想单独分开运行多次 就需要用半连接池。

作用:设置的最大等待人数可以节省资源,提高效率。

server.listen(5) 

TCP黏包问题及解决思路

黏包问题

TCP协议的特点是会将数据量比较小并且时间间隔比较短的数据整合到一起发送,并且还会受制于recv括号内的数字大小。因为tcp协议是流式协议,跟水流一样不间断

问题:传入的3次数据被合成一个

问题产生的原因其实是因为recv括号内我们不知道即将要接收的数据到底多大,如果每次接收的数据我们都能够精确的知道它的大小,那么肯定不会出现黏包。

思路:精准的知道数据量多大,那么黏包问题就自动解决了

解决思路

可以利用struct模块精准的获取数据的大小。

思路:
1.先将真实数据打包成固定长度的包
2.将固定长度的包先发给对方
3.对方接收到包之后再解包获取真实数据长度
4.接收真实数据长度

小问题:负责打包的方法数据量如果特别巨大是无法打包的。

终极解决方案:利用字典存储数据,不但有数据的长度,还可以携带额外的数据。

发送端的思路:

 1.先构造一个字典 
        内部存档了真实数据相关的信息
            大小 名称 简介 ...
2.对字典做打包处理
3.将固定长度的数据(字典)发送给对方
4.发送真实的字典数据
5.发送真实的真正数据

接收端的思路:

1.先接收固定长度的字典包
2.解析出字典的真实长度
3.接收字典数据
4.从字典数据中解析出各种信息
5.接收真实的数据
posted @   空白o  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示