1本のスティックパック現象
服务端: 客户端:
第一次 dir 数据 < 1024 接收所有数据
第二次 ipconfig 数据 > 1024 接收1024个字节
第三次 dir 数据 < 1024 接收上次剩下的字节
TCP协议的流式协议,数据与水流一样源源不断 => 粘包现象
黏包现象的根本原因:缓冲区
缓冲区的作用:如果网络出现短暂的异常或者波动,接收数据就会出现出现短暂的中断,影响下载或上传的效率
什么情况下黏包现象产生黏包?
1.recv会产生黏包(如果recv接受的数据量(1024)小于发送的数据量,第一次只能接收规定的数据量1024,第二次接受剩余的数据量)
2.send也可能发生黏包现象(连续send少量的数据发到输出缓冲区,由于缓冲区的机制,可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络)
2.ソリューションスティッキーパッケージ
思路分析:
1.当第二次给服务器发送命令之前,应该循环recv直至将所用的数据全部取完
3000bytes => recv3次
5000bytes => recv5次
30000bytes => recv30次
2.限制循环次数:当发送的总bytes个数,与接收的总bytes个数相等时,循环结束
3.如何获取发送的总bytes个数 => len()
4.总bytes个数的类型
将int转化成bytes,但无论总字节个数是多少,都应确保转化成固定长度的bytes,以此方便获取头部信息
通过struct将总bytes个数转化成固定的4个字节 => low版
总bytes个数过大时,使用struct会报错 => 旗舰版
low版:
服务端
import socket
import subprocess
import struct
phone = socket.socket()
phone.bind(('127.0.0.1',8848))
phone.listen(5)
conn,addr = phone.accept()
while 1:
try:
client_data=conn.recv(1024)
obj = subprocess.Popen(client_data.decode('utf-8'),
shell = True,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
result = obj.stdout.read()+obj.stderr.read()
total_size = len(result)
total_size_bytes = struct.pack('i',total_size)
conn.send(total_size_bytes)
conn.send(result)
except ConnectionResetError :
break
conn.close()
phone.close()
客户端
import socket
import struct
phone = socket.socket()
phone.connect(('127.0.0.1',8848))
while 1:
content = input('输入:')
if content.upper() == 'Q':
break
phone.send(content.encode('utf-8'))
head_bytes = phone.recv(4)
total_size = struct.unpack('i',head_bytes)[0]
total_data = b''
while len(total_data)<total_size:
total_data += phone.recv(1024)
print(total_data.decode('gbk'))
phone.close()
旗舰版:
服务端
import socket
import subprocess
import struct
import json
phone = socket.socket()
phone.bind(('127.0.0.1', 8888))
phone.listen(5)
conn, addr = phone.accept()
while 1:
try:
cmd = conn.recv(1024)
obj = subprocess.Popen(cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,)
result = obj.stdout.read() + obj.stderr.read()
result = result.decode('gbk').encode('utf-8')
# 1. 制作报头
head_dict = {
'MD5': '7a6f150b83091ce20c89368641f9a137',
'file_name': '蔡徐坤篮球秀',
'file_size': len(result),
}
# 2. 将报头字典转化成json字符串
head_dict_json = json.dumps(head_dict)
# 3. 将json字符串 转化成bytes
head_dict_json_bytes = head_dict_json.encode('utf-8')
# 4. 获取报头的长度
head_len = len(head_dict_json_bytes)
# 5.将长度转化成固定的4个字节
head_len_bytes = struct.pack('i',head_len)
# 6. 发送固定的4个字节
conn.send(head_len_bytes)
# 7. 发送报头
conn.send(head_dict_json_bytes)
# 8. 发送原数据
conn.send(result)
except ConnectionResetError:
break
conn.close()
phone.close()
客户端
import socket
import struct
import json
phone = socket.socket()
phone.connect(('127.0.0.1',8888))
while 1:
content = input('输入:')
if content.upper() == 'Q':
break
phone.send(content.encode('utf-8'))
head_len_bytes = phone.recv(4)
head_len = struct.unpack('i',head_len_bytes)[0]
head_dict_json_bytes = phone.recv(head_len)
head_dict_json = head_dict_json_bytes.decode('utf-8')
head_dict = json.loads(head_dict_json)
total_data = b''
while len(total_data)<head_dict['file_size']:
total_data += phone.recv(1024)
print(total_data.decode('utf-8'))
phone.close()