目录
1.黏包的问题
2.解决黏包问题
3.文件上传下载
4.struct模块使用
1.黏包的问题
#CMD服务端
import socket
import subprocess
import struct
server = socket.socket()
server.bind(("127.0.0.1",9090))
server.listen()
while True:
client,addr = server.accept()
while True:
try:
# 接收命令
cmd = client.recv(1024).decode("utf-8")
p = subprocess.Popen(cmd,shell=True,stdout=-1,stderr=-1)
# data与err_data 都是采用的系统编码 windows是GBK
data = p.stdout.read()
err_data = p.stderr.read()
print("数据长度:%s" % (len(data) + len(err_data)))
# 先发送长度给客户端
length = len(data) + len(err_data)
len_data = struct.pack("i",length)
# 先发送长度 在发真实数据 有可能 长度数据和真实数据黏在一起 而接收方不知道长度数据的字节数 导致黏包
# 解决的方案就是 长度信息占的字节数固定死 整数 转成一个固定长度字节
client.send(len_data)
client.send(data)
client.send(err_data)
except ConnectionResetError:
client.close()
print("连接中断......")
break
#CMD客户端
import struct
import socket
c = socket.socket()
c.connect(("127.0.0.1",9090))
while True:
cmd = input(">>:").strip()
c.send(cmd.encode("utf-8"))
# 先接收长度 长度固定为4个字节
length = c.recv(4)
len_data = struct.unpack("i",length)[0] # 转换为整型
print("数据长度为%s" % len_data)
all_data = b"" # 存储已接收数据
rcv_size = 0 # 已接收长度
# 接收真实数据
# 循环接收 直到 接收到的长度等于总长度
while rcv_size < len_data:
data = c.recv(1024)
rcv_size += len(data)
all_data += data
print("接收长度%s" % rcv_size)
print(all_data.decode("gbk"))
2.解决黏包问题
#CMD服务端
import socket
import subprocess
import struct
import datetime
import json
server = socket.socket()
server.bind(("127.0.0.1",9090))
server.listen()
# 要求 不仅返回命令的结果 还要返回执行命令的时间 执行时间:2018/12/26
while True:
client,addr = server.accept()
while True:
try:
# 接收命令
cmd = client.recv(1024).decode("utf-8")
p = subprocess.Popen(cmd,shell=True,stdout=-1,stderr=-1)
# data与err_data 都是采用的系统编码 windows是GBK
data = p.stdout.read()
err_data = p.stderr.read()
print("数据长度:%s" % (len(data) + len(err_data)))
# 计算真实数据长度
length = len(data) + len(err_data)
# 在发送数据之前发送额外的信息
#t = "{执行时间:%s 真实数据长度:%s" % (datetime.datetime.now(),length)
# 把要发送的数据先存到字典中
t = {}
t["time"] = str(datetime.datetime.now())
t["size"] = length
t["filename"] = "a.mp4"
t_json = json.dumps(t) # 得到json格式字符串
t_data = t_json.encode("utf-8") # 将json转成了字节
t_length = struct.pack("i",len(t_data))
# 1.先发送额外信息的长度
client.send(t_length)
# 2.发送额外信息
client.send(t_data)
# 3.发送真实数据
client.send(data)
client.send(err_data)
except ConnectionResetError:
client.close()
print("连接中断......")
break
# 1.发送了真实数据长度 2.发送了额外信息长度 3.发送额外信息 4.真实数据
#CMD客户端
import struct
import socket
import json
c = socket.socket()
c.connect(("127.0.0.1",9090))
while True:
cmd = input(">>:")
if not cmd:
print("命令不能为空")
continue
c.send(cmd.encode("utf-8"))
# 1.接收的是额外信息的长度
length = c.recv(4)
len_data = struct.unpack("i",length)[0] # 转换为整型
# 2.接收额外信息
t_data = c.recv(len_data)
print(t_data.decode("utf-8"))
json_dic = json.loads(t_data.decode("utf-8"))
print("执行时间:%s" % json_dic["time"])
data_size = json_dic["size"] # 得到数据长度
# 3.接收真实数据
all_data = b"" # 存储已接收数据
rcv_size = 0 # 已接收长度
# 接收真实数据
# 循环接收 直到 接收到的长度等于总长度
while rcv_size < data_size:
data = c.recv(1024)
rcv_size += len(data)
all_data += data
print("接收长度%s" % rcv_size)
print(all_data.decode("gbk"))
3.文件上传下载
"""
1.应该采用TCP 必须保证数据时完整的
2.只能传输bytes类型 刚好 文件操作 读取和写入都是bytes类型
3.上传的思路
自定义报头 发送文件名 文件大小 md5值
读取文件数据 发送给对方
"""
#服务端
import socket
import struct
import json
server = socket.socket()
server.bind(("127.0.0.1",9090))
server.listen()
client,addr = server.accept()
f = open("接收到的文件",mode="wb")
head_len = client.recv(4)
json_len = struct.unpack("i",head_len)[0]
json_str = client.recv(json_len).decode("utf-8")
head = json.loads(json_str)
print(head)
recv_size = 0
while recv_size < head["size"]:
data = client.recv(1024)
f.write(data)
recv_size += len(data)
print("接收完成...")
#客户端
import socket
import os
import json
import struct
c = socket.socket()
c.connect(("127.0.0.1",9090))
filepath= r"D:\脱产5期内容\day30\视频\1.上周回顾.mp4"
f = open(filepath,mode="rb")
# 在发送数据前先发送报头
head = {"size":os.path.getsize(filepath),"filename":"回顾.mp4"}
json_data = json.dumps(head).encode("utf-8")
json_len = struct.pack("i",len(json_data))
c.send(json_len) # 发长度
c.send(json_data) # 发报头
# 发数据
while True:
data = f.read(1024)
if not data:
break
# 发送给服务器
c.send(data)
print("上传完成...")
4.struct模块的使用
"""
struct结构体
可以将python中的数据类型 转换成bytes
"""
num = 1024
import struct
# 该函数 将一个python的数据转成bytes 第一个参数通常是i 其能转换的数据范围是c语言的int范围
# 如果int不够 那就用q 表示long long 型
res = struct.pack("i",num)
print(res)
print(len(res))
# 从字节转回整型
res2 = struct.unpack("i",res)
print(res2[0])