目錄
1.黏包的問(wèn)題
2.解決黏包問(wèn)題
3.文件上傳下載
4.struct模塊使用
1.黏包的問(wèn)題
#CMD服務(wù)端
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 都是采用的系統(tǒng)編碼 windows是GBK
data = p.stdout.read()
err_data = p.stderr.read()
print("數(shù)據(jù)長(zhǎng)度:%s" % (len(data) + len(err_data)))
# 先發(fā)送長(zhǎng)度給客戶端
length = len(data) + len(err_data)
len_data = struct.pack("i",length)
# 先發(fā)送長(zhǎng)度 在發(fā)真實(shí)數(shù)據(jù) 有可能 長(zhǎng)度數(shù)據(jù)和真實(shí)數(shù)據(jù)黏在一起 而接收方不知道長(zhǎng)度數(shù)據(jù)的字節(jié)數(shù) 導(dǎo)致黏包
# 解決的方案就是 長(zhǎng)度信息占的字節(jié)數(shù)固定死 整數(shù) 轉(zhuǎn)成一個(gè)固定長(zhǎng)度字節(jié)
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"))
# 先接收長(zhǎng)度 長(zhǎng)度固定為4個(gè)字節(jié)
length = c.recv(4)
len_data = struct.unpack("i",length)[0] # 轉(zhuǎn)換為整型
print("數(shù)據(jù)長(zhǎng)度為%s" % len_data)
all_data = b"" # 存儲(chǔ)已接收數(shù)據(jù)
rcv_size = 0 # 已接收長(zhǎng)度
# 接收真實(shí)數(shù)據(jù)
# 循環(huán)接收 直到 接收到的長(zhǎng)度等于總長(zhǎng)度
while rcv_size < len_data:
data = c.recv(1024)
rcv_size += len(data)
all_data += data
print("接收長(zhǎng)度%s" % rcv_size)
print(all_data.decode("gbk"))
2.解決黏包問(wèn)題
#CMD服務(wù)端
import socket
import subprocess
import struct
import datetime
import json
server = socket.socket()
server.bind(("127.0.0.1",9090))
server.listen()
# 要求 不僅返回命令的結(jié)果 還要返回執(zhí)行命令的時(shí)間 執(zhí)行時(shí)間: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 都是采用的系統(tǒng)編碼 windows是GBK
data = p.stdout.read()
err_data = p.stderr.read()
print("數(shù)據(jù)長(zhǎng)度:%s" % (len(data) + len(err_data)))
# 計(jì)算真實(shí)數(shù)據(jù)長(zhǎng)度
length = len(data) + len(err_data)
# 在發(fā)送數(shù)據(jù)之前發(fā)送額外的信息
#t = "{執(zhí)行時(shí)間:%s 真實(shí)數(shù)據(jù)長(zhǎng)度:%s" % (datetime.datetime.now(),length)
# 把要發(fā)送的數(shù)據(jù)先存到字典中
t = {}
t["time"] = str(datetime.datetime.now())
t["size"] = length
t["filename"] = "a.mp4"
t_json = json.dumps(t) # 得到j(luò)son格式字符串
t_data = t_json.encode("utf-8") # 將json轉(zhuǎn)成了字節(jié)
t_length = struct.pack("i",len(t_data))
# 1.先發(fā)送額外信息的長(zhǎng)度
client.send(t_length)
# 2.發(fā)送額外信息
client.send(t_data)
# 3.發(fā)送真實(shí)數(shù)據(jù)
client.send(data)
client.send(err_data)
except ConnectionResetError:
client.close()
print("連接中斷......")
break
# 1.發(fā)送了真實(shí)數(shù)據(jù)長(zhǎng)度 2.發(fā)送了額外信息長(zhǎng)度 3.發(fā)送額外信息 4.真實(shí)數(shù)據(jù)
#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.接收的是額外信息的長(zhǎng)度
length = c.recv(4)
len_data = struct.unpack("i",length)[0] # 轉(zhuǎn)換為整型
# 2.接收額外信息
t_data = c.recv(len_data)
print(t_data.decode("utf-8"))
json_dic = json.loads(t_data.decode("utf-8"))
print("執(zhí)行時(shí)間:%s" % json_dic["time"])
data_size = json_dic["size"] # 得到數(shù)據(jù)長(zhǎng)度
# 3.接收真實(shí)數(shù)據(jù)
all_data = b"" # 存儲(chǔ)已接收數(shù)據(jù)
rcv_size = 0 # 已接收長(zhǎng)度
# 接收真實(shí)數(shù)據(jù)
# 循環(huán)接收 直到 接收到的長(zhǎng)度等于總長(zhǎng)度
while rcv_size < data_size:
data = c.recv(1024)
rcv_size += len(data)
all_data += data
print("接收長(zhǎng)度%s" % rcv_size)
print(all_data.decode("gbk"))
3.文件上傳下載
"""
1.應(yīng)該采用TCP 必須保證數(shù)據(jù)時(shí)完整的
2.只能傳輸bytes類型 剛好 文件操作 讀取和寫入都是bytes類型
3.上傳的思路
自定義報(bào)頭 發(fā)送文件名 文件大小 md5值
讀取文件數(shù)據(jù) 發(fā)送給對(duì)方
"""
#服務(wù)端
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:\脫產(chǎn)5期內(nèi)容\day30\視頻\1.上周回顧.mp4"
f = open(filepath,mode="rb")
# 在發(fā)送數(shù)據(jù)前先發(fā)送報(bào)頭
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) # 發(fā)長(zhǎng)度
c.send(json_data) # 發(fā)報(bào)頭
# 發(fā)數(shù)據(jù)
while True:
data = f.read(1024)
if not data:
break
# 發(fā)送給服務(wù)器
c.send(data)
print("上傳完成...")
4.struct模塊的使用
"""
struct結(jié)構(gòu)體
可以將python中的數(shù)據(jù)類型 轉(zhuǎn)換成bytes
"""
num = 1024
import struct
# 該函數(shù) 將一個(gè)python的數(shù)據(jù)轉(zhuǎn)成bytes 第一個(gè)參數(shù)通常是i 其能轉(zhuǎn)換的數(shù)據(jù)范圍是c語(yǔ)言的int范圍
# 如果int不夠 那就用q 表示long long 型
res = struct.pack("i",num)
print(res)
print(len(res))
# 從字節(jié)轉(zhuǎn)回整型
res2 = struct.unpack("i",res)
print(res2[0])