25.并发编制【一】操作系统
【一】socketserver
import socket
import struct
import json
import os
# 定义处理器类
class MYTCPClient:
# 定义套接字家族
address_family = socket.AF_INET
# 定义协议类型
socket_type = socket.SOCK_STREAM
# 定义拒绝地址(黑名单)
allow_reuse_address = False
# 最大传输包大小
max_packet_size = 8192
# 默认编码格式
coding = 'utf-8'
# 最大请求次数
request_queue_size = 5
def __init__(self, server_address, connect=True):
# 获取服务端地址
self.server_address = server_address
# 创建 socket 对象
self.socket = socket.socket(self.address_family,
self.socket_type)
# 判断当前是否链接
if connect:
try:
self.client_connect()
except:
self.client_close()
raise
# 定义连接方法
def client_connect(self):
# 连接指定服务端
self.socket.connect(self.server_address)
# 关闭连接
def client_close(self):
self.socket.close()
# 启动函数
def run(self):
# 多次循环
while True:
# 输入指令 put 文件路径
inp = input(">>: ").strip()
if not inp: continue
# 切分指令
l = inp.split() # ['put','文件路径']
# 获取cmd命令
cmd = l[0]
# 判断自己当前是否含有该方法
if hasattr(self, cmd):
func = getattr(self, cmd)
func(l)
# 定义上传函数
def put(self, args):
# ['put','文件路径']
cmd = args[0] # 'put'
filename = args[1] # '文件路径'
if not os.path.isfile(filename):
print('file:%s is not exists' % filename)
return
else:
filesize = os.path.getsize(filename)
# 粘包处理 --- 打包
head_dic = {'cmd': cmd, 'filename': os.path.basename(filename), 'filesize': filesize}
print(head_dic)
head_json = json.dumps(head_dic)
head_json_bytes = bytes(head_json, encoding=self.coding)
# 打包
head_struct = struct.pack('i', len(head_json_bytes))
# 传输包长度
self.socket.send(head_struct)
# 传输打包数据
self.socket.send(head_json_bytes)
send_size = 0
# 打开文件,上传文件
with open(filename, 'rb') as f:
for line in f:
self.socket.send(line)
send_size += len(line)
print(send_size)
else:
print('upload successful')
client = MYTCPClient(('127.0.0.1', 8080))
client.run()
import socketserver
import struct
import json
import os
# 创建服务类,继承了 socketserver.BaseRequestHandler , 基本的处理类
class FtpServer(socketserver.BaseRequestHandler):
# 定义编码格式
coding = 'utf-8'
# 定义服务文件路径
server_dir = 'file_upload'
# 定义一次性最大传输
max_packet_size = 1024
# 定义根路径
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# 文件处理函数
def handle(self):
# 查看自己的request请求
print(self.request)
# 创建循环
while True:
# 调用自己的请求对象接收数据
data = self.request.recv(4)
# 数据解包
data_len = struct.unpack('i', data)[0]
# 取出打好的头
head_json = self.request.recv(data_len).decode(self.coding)
# 转数据格式
head_dic = json.loads(head_json)
# {'cmd': cmd, 'filename': os.path.basename(filename), 'filesize': filesize}
# print(head_dic)
# 获取命令
cmd = head_dic['cmd']
# 判断当前自己是否具有该方法
if hasattr(self, cmd):
func = getattr(self, cmd)
func(head_dic)
def _create_filename(self, path):
if not os.path.exists(path):
os.mkdir(path)
# 定义上传处理函数
def put(self, args):
# 定义文件路径
file_path = os.path.normpath(os.path.join(
self.BASE_DIR,
self.server_dir,
args['filename']
))
# 创建上传文件存储路径 ..\file_upload\
self._create_filename(os.path.join(self.BASE_DIR, self.server_dir))
# 取出文件大小
filesize = args['filesize']
# 定义起始文件接收量
recv_size = 0
print('----->', file_path)
# 打开文件,保存文件数据
with open(file_path, 'wb') as f:
while recv_size < filesize:
recv_data = self.request.recv(self.max_packet_size)
f.write(recv_data)
recv_size += len(recv_data)
print('recvsize:%s filesize:%s' % (recv_size, filesize))
ftpserver = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), FtpServer)
ftpserver.serve_forever()
'''
# data : 总的二进制数据
for line in data:
with opem(file,'wb') as fp:
fp.write(line)
# data : 总的二进制数据
with opem(file,'wb') as fp:
for line in data:
fp.write(line)
'''
【二】操作系统
1)进程
进程就是在电脑上正在执行的一个过程,其来源于操作系统,是操作系统最核心的概念
2)为什么有操作系统
- 程序员无法把所有的硬件操作细节都了解到
- 管理这些硬件并且加以优化使用是非常繁琐的工作,这个繁琐的工作就是操作系统来干的
- 有了他,程序员就从这些繁琐的工作中解脱了出来,只需要考虑自己的应用软件的编写就可以了
- 应用软件直接使用操作系统提供的功能来间接使用硬件。
3)什么的操作系统
就是一个协调、管理和控制计算机硬件资源和软件资源的控制程序
位于计算机硬件与应用软件之间,本质也是一个软件
4)功能
1.隐藏硬件接口
- 隐藏了丑陋的硬件调用接口,为应用程序员提供调用硬件资源更好,更简单,更清晰的模型
- 不用再考虑操作硬件的细节
2.资源有序化
- 将应用程序对硬件资源的竞争请求变得有序化
3.对资源进行合理的调度和分配
- 记录哪个程序使用什么资源
- 对资源请求进行分配
- 为不同的程序和用户调解互相冲突的资源请求。
5)如何实现资源有序化
1.时间上的复用
- 一个资源在时间上复用时,不同的程序或用户轮流使用
2.空间上的复用
- 每个客户都获取了一个大的资源中的一小部分资源,从而减少了排队等待资源的时间。
3.多道技术(时间上的复用 + 空间上的复用)
6)操作系统和普通软件的区别
- 操作系统是普通软件运行的载体
- 操作系统比较大
- 操作系统寿命比较长
【三】操作系统发展史
1)第一代计算机 (1940-1955)
真空管和穿孔卡片
当时发明的一个主要思路就是想用机械没有生命的铁疙瘩代替一部分人力
计算机的发明标志着人类从机械时代进入到电子时代
第二次时间大战:投入计算机,刺激了计算机的发展
节省一部分计算机操作
用高低电频 --> 用 0 / 1 去编程 --> 用真空管或者穿孔卡片 来代表一部分汇编指令
让计算机去读取指定的卡片的位置 0 / 1
工作流程 :
-
程序员在墙上的机时表预约一段时间
-
然后程序员拿着他的插件版到机房里
-
将自己的插件板街道计算机里
-
这几个小时内他独享整个计算机资源
-
后面的一批人都得等着(两万多个真空管经常会有被烧坏的情况出现)。
-
后来出现了穿孔卡片,可以将程序写在卡片上,然后读入机而不用插件板
如果一旦你卡片位置写错了:导致你得从头再来
优点:就是程序员可以在指定的时间内I独享整个资源
缺点:浪费计算机资源,串行
串行就是一条串 10s
并行就是两个人一起走 5s
2)第二代计算机
晶体管和批处理系统
当时的计算机非常昂贵:自然而然的想要减少资源的浪费
-
设计人员、生产人员、操作人员、程序人员和维护人员直接有了明确的分工
-
计算机被锁在专用空调房间中 : 现在的服务器很像
-
由专业操作人员运行,这便是‘大型机’。
出现了磁带:复读机 --> 次代种包含了电流信息
3)第三代计算
集成电路芯片和多道程序设计
-
IBM公司试图通过引入system/360系列来同时满足科学计算和商业计算
-
360系列低档机与1401相当,高档机比7094功能强很多
-
不同的性能卖不同的价格
-
360是第一个采用了(小规模)芯片(集成电路)的主流机型
- 与采用晶体管的第二代计算机相比,性价比有了很大的提高。
- 这些计算机的后代仍在大型的计算机中心里使用,此乃现在服务器的前身
- 这些服务器每秒处理不小于千次的请求。
如何解决第二代计算机的问题1
-
卡片被拿到机房后能够很快的将作业从卡片读入磁盘,于是任何时刻当一个作业结束时,操作系统就能将一个作业从磁带读出,装进空出来的内存区域运行,这种技术叫做 同时的外部设备联机操作:SPOOLING
-
该技术同时用于输出。
-
当采用了这种技术后,就不在需要IBM1401机了,也不必将磁带搬来搬去了(中间俩小人不再需要)
如何解决第二代计算机的问题2
-
第三代计算机的操作系统广泛应用了第二代计算机的操作系统没有的关键技术:
- 多道技术
-
cpu在执行一个任务的过程中
-
若需要操作硬盘,则发送操作硬盘的指令
-
指令一旦发出,硬盘上的机械手臂滑动读取数据到内存中
-
这一段时间,cpu需要等待,时间可能很短
-
但对于cpu来说已经很长很长,长到可以让cpu做很多其他的任务
-
如果我们让cpu在这段时间内切换到去做其他的任务
-
这样cpu不就充分利用了吗。这正是多道技术产生的技术背景
-
4)个人计算机
有了单独的CPU和内存
每个部分负责响应的功能
6)小结
1.操作系统的作用
-
隐藏丑陋复杂的硬件接口,提供良好的抽象接口
-
管理、调度进程,并且将多个进程对硬件的竞争变得有序
2.多道技术
(1)产生背景:针对单核,实现并发
- 现在的主机一般是多核,那么每个核都会利用多道技术 有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个cpu中的任意一个,具体由操作系统调度算法决定。
(2)空间上的复用:如内存中同时有多道程序
- 空间上的复用指的是在内存中同时运行多个程序,这样可以有效地利用内存资源。
(3)时间上的复用:复用一个cpu的时间片
-
指共享同一台机器的多个进程可以轮流使用CPU,从而避免了长时间等待的情况发生。
-
强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样才能保证下次切换回来时,能基于上次切走的位置继续运行
3.操作系统发展史
-
第一代计算机(1940~1955):真空管和穿孔卡片
-
第二代计算机(1955~1965):晶体管和批处理系统
-
第三代计算机(1965~1980):集成电路芯片和多道程序设计
-
第四代计算机(1980~至今):个人计算机