黏包现象
1.服务端连续执行三次recv
2.客户端连续执行三次send
问题:服务端一次性接收到了客户端三次的消息,这种现象称为'黏包现象'
黏包现象产生的原因
1.不知道每次的数据到底有多大
2.TCP也称为流式协议:数据象水流一样绵绵不绝没有间隔(TCP会针对数据量较小且发送间隔较短的多条数据一次性合并打包发送)
避免黏包现象的核心思路\关键点
怎么样才能明确接收的数据具体有多大
ps:如何将长度变化的数据全部制作成固定长度的数据
struct模块
import struct
info = b'hello big baby'
print(len(info)) # 14
# 将数据打包成固定的长度,i是固定的打包模式
res = struct.pack('i', len(info))
# 打包之后长度为(bytes)4 报头
print(len(res))
real_len = struct.unpack('i', res)
print(real_len) # (14,) 根据固定长度的报头,解析出真实数据的长
解决黏包问题初次版本
客户端
1.将真实数据转成bytes类型并计算长度
2.利用struct模块将真实长度制作一个固定长度的报头
3.将固定长度的报头先发给服务端 服务端只需要在recv括号内填写固定长度的报头数字即可
4.然后再发送真实数据
服务端
1.服务端先接收固定长度的报头
2.利用struct模块反向解析出真实数据长度
3,recv接收真实数据长度即可
解决过程中遇到的问题
问题1:
struct模块无法打包数据量较大的数据,就算换更大的模式也不行
问题2:
报头能否传递更多的信息 比如电影大小 电影名称 电影评价 电影简介
解决黏包问题终极解决方案
字典作为报头打包 效果更好 数字更小
import struct
data_dict = {
'file_name': 'xxx老师教学.avi',
'file_size': 123132131232342342423423423423432423432,
'file_info': '内容很精彩 千万不要错过',
'file_desc': '一代神作 私人珍藏'
}
import json
data_json = json.dumps(data_dict)
print(len(data_json.encode('utf8'))) # 真实字典的长度 228
res = struct.pack('i', len(data_json.encode('utf8')))
print(len(res))
黏包代码实战
服务端
import socket
import struct
import json
server = socket.socket()
server.bind(('127.0.0.1', 8081))
server.listen(5)
sock, addr = server.accept()
# 1.接收固定长度的字典报头
data_dict_head = sock.recv(4)
# 2.根据报头解析出字典数据的长度
data_dict_len = struct.unpack('i', data_dict_head)[0]
# 3.接收字典数据
data_dict_bytes = sock.recv(data_dict_len)
data_dict = json.loads(data_dict_bytes) # 自动解码再反序列化
# 4.获取真实数据的各项信息
# total_size = data_dict.get('file_size')
# with open(data_dict.get('file_name'), 'wb') as f:
# f.write(sock.recv(total_size))
'''接收真实数据的时候 如果数据量非常大 recv括号内直接填写该数据量 不太合适 我们可以每次接收一点点 反正知道总长度'''
# total_size = data_dict.get('file_size')
# recv_size = 0
# with open(data_dict.get('file_name'), 'wb') as f:
# while recv_size < total_size:
# data = sock.recv(1024)
# f.write(data)
# recv_size += len(data)
# print(recv_size)
客户端
import socket
import os
import struct
import json
client = socket.socket()
client.connect(('127.0.0.1', 8081))
'''任何文件都是下列思路 图片 视频 文本 ...'''
# 1.获取真实数据大小
file_size = os.path.getsize(r'/Users/jiboyuan/PycharmProjects/day36/xx老师合集.txt')
# 2.制作真实数据的字典数据
data_dict = {
'file_name': '有你好看.txt',
'file_size': file_size,
'file_desc': '内容很长 准备好吃喝 我觉得营养快线挺好喝',
'file_info': '这是我的私人珍藏'
}
# 3.制作字典报头
data_dict_bytes = json.dumps(data_dict).encode('utf8')
data_dict_len = struct.pack('i', len(data_dict_bytes))
# 4.发送字典报头
client.send(data_dict_len) # 报头本身也是bytes类型 我们在看的时候用len长度是4
# 5.发送字典
client.send(data_dict_bytes)
# 6.最后发送真实数据
with open(r'/Users/jiboyuan/PycharmProjects/day36/xx老师合集.txt', 'rb') as f:
for line in f: # 一行行发送 和直接一起发效果一样 因为TCP流式协议的特性
client.send(line)
import time
time.sleep(10)
UDP协议
1.UDP服务端和客户端'各自玩各自的'
2.UDP不会出现多个消息发送合并
并发编程理论
1.研究网络编程其实就是在研究计算机的底层原理及发展史
2.在计算机中真正干活的一直都是CPU
操作系统发展史
1.手工操作----穿孔卡片
1946年第一台计算机诞生-20世纪50年代中期,计算机工作还在采用手工操作方式。这个时候还没有操作系统的概念
程序员将对应于程序和数据的已穿孔的纸带(或者卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存,接着通过控制台开关启动程序针对数据运行,计算完毕,打印机输出计算结果,用户取走结果并卸下纸带(或卡片)后,才让下一个用户上机。
手工操作方式两个特点:
1.用户独占全机。(不会出现因资源已被其他用户占用而等待的现象,但资源的利用率低)
2.CPU等待手工操作。(CPU的利用不充分)
(2)CPU 等待手工操作。CPU的利用不充分。 20世纪50年代后期,出现人机矛盾:手工操作的慢速度和计算机的高速度之间形成了尖锐矛盾,手工操作方式已严重损害了系统资源的利用率(使资源利用率降为百分之几,甚至更低),不能容忍。唯一的解决办法:只有摆脱人的手工操作,实现作业的自动过渡。这样就出现了成批处理。 2、批处理 —— 磁带存储 批处理系统:加载在计算机上的一个系统软件,在它的控制下,计算机能够自动地、成批地处理一个或多个用户的作业(这作业包括程序、数据和命令)。 提前使用磁带一次性录入多个程序员编写的程序 然后交给计算机执行 CPU工作效率有所提升 不用反复等待程序录入 1.联机批处理系统 首先出现的是联机批处理系统,即作业的输入/输出由CPU来处理。
主机与输入机之间增加一个存储设备——磁带,在运行于主机上的监督程序的自动控制下,计算机可自动完成:成批地把输入机上的用户作业读入磁带,依次把磁带上的用户作业读入主机内存并执行并把计算结果向输出机输出。完成了上一批作业后,监督程序又从输入机上输入另一批作业,保存在磁带上,并按上述步骤重复处理。
监督程序不停地处理各个作业,从而实现了作业到作业的自动转接,减少了作业建立时间和手工操作时间,有效克服了人机矛盾,提高了计算机的利用率。
但是,在作业输入和结果输出时,主机的高速CPU仍处于空闲状态,等待慢速的输入/输出设备完成工作: 主机处于“忙等”状态。 2.脱机批处理系统 为克服与缓解:高速主机与慢速外设的矛盾,提高CPU的利用率,又引入了脱机批处理系统,即输入/输出脱离主机控制。
卫星机:一台不与主机直接相连而专门用于与输入/输出设备打交道的。
其功能是:
(1)从输入机上读取用户作业并放到输入磁带上。
(2)从输出磁带上读取执行结果并传给输出机。
这样,主机不是直接与慢速的输入/输出设备打交道,而是与速度相对较快的磁带机发生关系,有效缓解了主机与设备的矛盾。主机与卫星机可并行工作,二者分工明确,可以充分发挥主机的高速计算能力。
脱机批处理系统:20世纪60年代应用十分广泛,它极大缓解了人机矛盾及主机与外设的矛盾。
不足:每次主机内存中仅存放一道作业,每当它运行期间发出输入/输出(I/O)请求后,高速的CPU便处于等待低速的I/O完成状态,致使CPU空闲。
为改善CPU的利用率,又引入了多道程序系统。
多道技术
单道技术
所有的程序排队执行,过程中不能重合
多道技术
利用空闲时间提前准备其他数据,最大化提升CPU利用率
多道技术详细
1.切换
计算机的cpu在两种情况下会切换(不让你用,给别人用)
1.程序IO操作
输入、输出操作
2.程序长时间占用CPU
2.保存状态
CPU每次切换走之前都需要保存当前的操作,下次切换回来基于上次的进度继续执行
进程理论
进程与程序的区别
进程:正在运行的程序(被运行起来的)
程序:一堆死代码(还没有被运行起来的)
进程的调度算法
1.FCFS(先来先服务)
对短作业不友好
2,短作业优先调度
对长作业不友好
3.时间片轮法+多级反馈队列(目前还在用)
将时间均分,然后根据进程时间长短在分多个等级
等级越靠下表示耗时越长,每次分到的时间越多,但是优先级越低
进程的并行与并发
并行
多个进程同时执行,必须要有多个CPU参与,单个CPU无法实现并行
并发
多个进程看上去像同时执行,单个CPU可以实现,多个CPU肯定也可以
进程的三状态
就绪态
所有的进程在被CPU执行之前都必须先进入就绪态等待
运行态
CPU正在执行
阻塞态
进程运行过程中出现了IO操作,阻塞态无法直接进入运行态,需要先进入就绪态
标签:struct,黏包,编程,len,dict,报头,data,CPU
From: https://www.cnblogs.com/lvqingmei/p/16900562.html