问题解决:TypeError: a bytes-like object is required, not 'str'

本文介绍了一个Python Socket服务端程序,该程序接收客户端连接并发送当前时间。文章详细解释了如何在Python 3中使用socket模块和datetime模块实现这一功能,并解决了因Python版本差异导致的TypeError问题。

问题

import socket
import datetime

HOST = '0.0.0.0'
PORT = 3434

# AF_INET说明使用IPV4地址,SOCK_STREAM指明TCP
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)

while True:
    conn, addr = s.accept()
    print('Client %s connected!' % str(addr))
    dt = datetime.datetime.now()
    message = "Current time is " + str(dt)
    
    conn.send(message)
    
    print('Send: %s' % message)
    conn.close()

执行这个程序出现错误

TypeError: a bytes-like object is required, not 'str'

原因

Python2和Python3在Socket返回值解码上有区别,Python2读取到的数据是bytes

解决

只需要用上python的bytes和str两种类型转换的函数encode()、decode()即可!

str通过encode()方法可以编码为指定的bytes;

bytes通过decode()方法可以编码为指定的str。

更改后:

import socket
import datetime

HOST = '0.0.0.0'
PORT = 3434

# AF_INET说明使用IPV4地址,SOCK_STREAM指明TCP
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)

while True:
    conn, addr = s.accept()
    print('Client %s connected!' % str(addr))
    dt = datetime.datetime.now()
    message = "Current time is " + str(dt)
    
    conn.send(message.encode())
    
    print('Send: %s' % message)
    conn.close()

你再次遇到: ``` TypeError: a bytes-like object is required, not 'str' ``` 这个错误 **非常明确**:某个函数期望接收 `bytes` 类型数据,但你传入了 `str`(字符串)。 --- ## 🔍 常见出错位置 以下这些函数 **只接受 `bytes`,不接受 `str`**: ```python zlib.compress(data) # ❌ data 是 str → 报错 bz2.compress(data) # ❌ data 是 str → 报错 lzma.compress(data) # ❌ data 是 str → 报错 gzip.compress(data) # ❌ data 是 str → 报错 base64.b64encode(data) # ❌ data 是 str → 报错(Python 3 严格模式) ``` > ✅ 它们都要求:`data` 必须是 `bytes` 类型! --- ## ✅ 根本原因 + 解决方案 ### ❌ 错误示例(导致报错) ```python source = "print('hello')" data = source # ← 是 str! data = zlib.compress(data) # TypeError! ``` ### ✅ 正确做法:始终确保输入为 `bytes` ```python source = "print('hello')" data = source.encode('utf-8') # str → bytes data = zlib.compress(data) # ✅ 成功压缩 ``` --- ## ✅ 修复后的完整加密流程(防错版) 下面是一个 **完全健壮、不会出现 `TypeError` 的多层加密函数**,支持任意顺序组合:`base64`, `zlib`, `bz2`, `lzma`, `gzip`。 ```python # -*- coding: utf-8 -*- import base64 import zlib import bz2 import lzma import gzip def encrypt_script(source_code: str, methods_order: list) -> str: """ 将 Python 源码按指定顺序进行多层加密,生成可运行的混淆脚本 :param source_code: 原始源码 (str) :param methods_order: 加密顺序列表,如 ['base64', 'gzip', 'lzma'] :return: 可运行的加密脚本 (str) """ # 支持的方法定义 ENCODERS = { 'base64': { 'encode': lambda d: base64.b64encode(d), 'import': 'import base64', 'call': 'base64.b64decode({})' }, 'zlib': { 'encode': lambda d: zlib.compress(d), 'import': 'import zlib', 'call': 'zlib.decompress({})' }, 'bz2': { 'encode': lambda d: bz2.compress(d), 'import': 'import bz2', 'call': 'bz2.decompress({})' }, 'lzma': { 'encode': lambda d: lzma.compress(d), 'import': 'import lzma', 'call': 'lzma.decompress({})' }, 'gzip': { 'encode': lambda d: gzip.compress(d), 'import': 'import gzip', 'call': 'gzip.decompress({})' } } # 输入验证 if not isinstance(source_code, str): raise TypeError("source_code 必须是字符串") if not methods_order: raise ValueError("加密方法不能为空") for method in methods_order: if method not in ENCODERS: raise ValueError(f"不支持的方法: {method}") # === 第一步:将源码转为 bytes === data = source_code.encode('utf-8') # str → bytes imports = set() call_chain = "data" # 构建最终执行链 # === 第二步:逐层加密(每层必须输入 bytes)=== for method in methods_order: encoder = ENCODERS[method] if not isinstance(data, bytes): raise TypeError(f"传递给 {method} 的数据不是 bytes,而是 {type(data).__name__}") try: data = encoder['encode'](data) # 所有 encode 函数输出都是 bytes imports.add(encoder['import']) except Exception as e: raise RuntimeError(f"加密失败 [{method}]: {str(e)}") # === 第三步:将最终结果 base64 编码成字符串用于嵌入脚本 === try: final_data_b64 = base64.b64encode(data).decode('ascii') # bytes → str except Exception as e: raise RuntimeError(f"Base64 编码失败: {str(e)}") # === 第四步:构建反向解压链(从外到内)=== for method in reversed(methods_order): encoder = ENCODERS[method] call_chain = encoder['call'].format(call_chain) # === 第五步:拼接完整脚本 === lines = [ '# -*- coding: utf-8 -*-', '""" 自动生成的加密脚本 """', *sorted(imports), f'data = {repr(final_data_b64)}', f'exec({call_chain}.decode("utf-8"))' ] return '\n'.join(lines) # ============================= # ✅ 测试用例 # ============================= if __name__ == "__main__": test_src = ''' print("🔓 脚本正在运行...") for i in range(3): print(f"第 {i+1} 层解密完成") print("✅ 执行结束") ''' # 自定义加密顺序(你可以随意更改) order = ['base64', 'gzip', 'lzma', 'zlib', 'bz2'] try: result = encrypt_script(test_src, order) print("=" * 60) print("✅ 生成成功!以下是可运行脚本:\n") print(result) print("\n🧪 正在本地执行验证...\n") exec(result) # 验证是否能正确运行 except Exception as e: print(f"❌ 错误:{type(e).__name__}: {e}") ``` --- ## ✅ 关键修复点总结 | 问题 | 如何解决 | |------|----------| | `TypeError: a bytes-like object is required` | 所有压缩前先 `.encode('utf-8')` | | 中间层传入 `str` | 每一层输出都是 `bytes`,绝不传 `str` | | `base64.b64encode()` 报错 | 确保输入是 `bytes`,输出后再 `.decode('ascii')` 变成字符串嵌入代码 | --- ## ✅ 数据流图(务必记住) ``` str (源码) ↓ .encode('utf-8') bytes → 给 compressors 使用(zlib/bz2/lzma/gzip/base64) ↓ 多层压缩后仍是 bytes ↓ base64.b64encode(...) → bytes ↓ .decode('ascii') → str(用于嵌入脚本) → 写入 data = "xxxx" → 运行时:base64.b64decode(data) → bytes → 解压链还原 → bytes → .decode('utf-8') → str → exec(...) ``` 📌 所有压缩器只处理 `bytes`,只有在写入脚本时才转成 `str`。 --- ## ✅ 常见错误对比表 | 错误写法 | 正确写法 | |--------|--------| | `zlib.compress("hello")` | `zlib.compress("hello".encode())` | | `data = base64.b64encode("abc")` | `data = base64.b64encode("abc".encode())` | | `exec(chain.decode())` 缺少 decode | `exec(...decode("utf-8"))` | --- ## ✅ 如何防止再犯? 加一个通用转换函数: ```python def ensure_bytes(d): """确保输入是 bytes""" if isinstance(d, str): return d.encode('utf-8') if isinstance(d, bytes): return d raise TypeError(f"不能转换为 bytes: {type(d)}") ``` 然后这样用: ```python data = ensure_bytes(source_code) for method in methods_order: data = ENCODERS[method]['encode'](ensure_bytes(data)) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值