粘包问题
内容概要
- 粘包现象
- 解决粘包逻辑思路
- 代码实操
- UDP基本代码使用
- 并发编程理论之操作系统发展史
- 多道技术
- 进程理论即调度算法
粘包现象
当发送端在短时间内发送多次较短的数据的时候
接收端会一次性把这些数据全部接收
-
粘包问题产生的原因
- 不知道每次的数据到底多大
- TCP也称之为流式协议:数据像水流一样不断没有间隔(TCP会针对数据量较小且发送间隔较短的多条数据一次性合并打包发送)
-
避免粘包现象的核心思路\关键点
如何明确即将接收的数据具体有多大
ps:如何将长度变化的数据全部制作成固定长度的数据
struct模块
import json
import struct
l1 = [1, 2, 3, 4, 5, 6, 7]
d1 = {
"name": "jason",
"age": "123"
}
# 1.因为字典没有办法转成字节类型 只有字符串可以转成字节类型
# 2.因为我们是为了发做准备 所以先把他转换成json格式 让接收方 但是解开的还是 原来的类型
# 比如 我传的字典 传过去打开还是字典
# res = struct.pack("i", json.dumps(l1).__len__()) # 第一参数传模式 第二个参数传数字 int类型
# res1 = struct.pack("i", json.dumps(d1).__len__())
#
# print(len(res)) # 4
# print(len(res1)) # 4
# res = struct.pack("i", len(l1))
# res1 = struct.pack("i", len(d1))
# print(len(res)) # 4
# print(len(res1)) # 4
不管多少 压缩后的长度都是 4
但是他也是有长度的限制的

解决粘包问题
服务端:
import struct
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", 8080))
server.listen(5)
sock, addr = server.accept() # 三次握手 建连接 返回管道 和 客户端的地址
# 发送先发送头 也就是 先告诉对方我要发送的数据的大小
data = "hello"
# 因为发送的字节形式 所以要发送的字节的长度
data_head = struct.pack("i", len(data.encode("utf8")))
sock.send(data_head)
sock.send(data.encode("utf8"))
data1 = "world"
data1_head = struct.pack("i", len(data1.encode("utf8")))
sock.send(data1_head)
sock.send(data1.encode("utf8"))
客户端:
import struct
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 8080))
data_head = client.recv(4)
data_len = struct.unpack("i", data_head)[0]
print(data_len)
data = client.recv(data_len)
print(data.decode("utf8"))
data1_head = client.recv(4)
data1_len = struct.unpack("i", data1_head)[0]
print(data1_len)
data1 = client.recv(data1_len)
print(data1.decode("utf8"))

"""
解决粘包问题初次版本
服务端:
1.将真实数据转化成bytes类型并计算长度
2.利用struct模块将真实长度制作一个固定长度的报头
3.将固定长度的报头发送给客户端 客户端只需要在recv括号内填写固定长度的报头数即可
4.然后再发送真实数据
客户端:
1.服务端先接收固定长度的报头
2.利用struct模块反向解析出真实数据的长度
3.recv接收真实数据长度即可
问题1:struct模块无法打包大量较大的数据 就算换更大的模式也不行
问题2:报头能否传递更多的信息 比如视频的大小 电影的名称
电影的简介
解决方案:字典作为报头打包 效果更好 数字更小
"""
终极方案
服务端:
import json
import struct
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", 8080))
server.listen(5)
sock, addr = server.accept()
dict_pack_head = sock.recv(4)
dict_pack_len = struct.unpack("i", dict_pack_head)[0]
dict_pack = sock.recv(dict_pack_len)
print(dict_pack)
data_dict = json.loads(dict_pack)
file_size = data_dict.get("file_size")
res_size = 0
with open(r"F:\pythonProject1\day36\aa\间谍过家家第12集.mp4", "wb")as f:
while res_size < file_size:
if (file_size - res_size) < 8192:
recv_size = (file_size - res_size)
else:
recv_size = 8192
data = sock.recv(recv_size)
f.write(data)
res_size += recv_size
客户端:
import json
import time
import struct
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# client.connect(("192.168.1.116", 8080))
client.connect(("127.0.0.1", 8080))
# client.connect(("192.168.1.51", 8080))
file_size = os.path.getsize("a1.mp4")
data_dict = {"file_name": "间谍过家家",
"file_size": file_size,
"file_desc": "嘎嘎好看"}
data_dict = json.dumps(data_dict)
data_head_len = struct.pack("i", len(data_dict.encode("utf8")))
client.send(data_head_len)
client.send(data_dict.encode("utf8"))
print(file_size)
res_size = 0
with open("a1.mp4", "rb")as f:
while res_size < file_size:
if (file_size - res_size) < 8192:
recv_size = (file_size - res_size)
else:
recv_size = 8192
time.sleep(0.00000000001)
data = f.read(recv_size)
client.send(data)
res_size += recv_size
print(res_size)
UDP协议
udp协议 他只管发 不管你收没有 服务端有没有运行
udp不会出现粘包问题
服务端:
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(("127.0.0.1", 8080))
data, addr = server.recvfrom(1024)
print(data.decode("utf8"))
print(addr)
客户端:
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = ("127.0.0.1", 8080)
date = "哈哈"
client.sendto(date.encode("utf8"), addr)

并发编程理论
研究网络编程其实就是研究计算机的底层原理及发展史
计算机中真正干活的是cpu
-
操作系统的发展史
-
穿孔卡片阶段
计算机很庞大 使用很麻烦 一次只能给一个人使用 期间很多时候计算机都不工作
好处:程序员可以独占计算机 为所欲为
坏处:计算机利用率太低 浪费资源
-
联机批处理系统
提前使用磁带一次性录入多个程序编写的程序 然后交给计算机执行
CPU工作效率有所提升 不用反复等待程序录入
-
脱机批处理系统
极大提升了CPU的利用率
-
时间片轮转法加多级反馈队列
他会这设置一个时间片,每个进程的只有这个时间片的时间拥有CPU当时间片到了进程有两种情况
- 时间到了进程刚好结束,那么会去运行下一个进程
- 时间到了进程还没有运行完会下方,然后去运行下一个进程,越往下的进程的优先级越低。
-
总结:操作系统的发展史 就是提升cpu利用率的过程
多道技术
-
单道技术
就是一个一个来 ,结束一个然后再运行下一个
-
多道技术
利用空闲的时间准备其他数据,最大化提升CPU利用率
多道技术详细
-
切换
计算机的CPU再两种情况下会切换
-
当程序有IO操作
输入输出操作
input、time.sleep、read、write -
程序长时间占用CPU
让多个程序都能被CPU运行一下
-
-
保存状态
CPU每次切走之前都需要保存当前的操作的状态 下次切换回来基于上次的进度继续执行
进程的并行于并发
-
并行
多个进程同时执行 必须要有多个CPU参与 单个CPU无法实现并行
也就并行几个进程 就需要多少个CPU
-
并发
多个进程看上去像同时进行 单个CPU可以实现 多个CPU肯定也可以
进程的三种状态
就绪态
所有的进程再被CPU执行之前都必须先进入就绪态等待
运行态
CPU正在执行
阻塞态
进程运行过程中出现了IO操作 阻塞无法直接进入运行态 需要先进入就绪态


浙公网安备 33010602011771号