You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python使用socket连接Telnet时recv接收内容无法解码问题

问题描述

在Python中通过socket模块连接23端口的Telnet服务时,调用recv方法接收返回数据,得到内容为b'\xff\xfb\x01\xff\xfb\x03\xff\xfd\x18\xff\xfd\x1f',无法解码为可读文本。已尝试Python支持的全部常见编码格式解码均未生效,尝试过的编码列表如下:

ascii big5 big5hkscs cp037 cp273 cp424 cp437 cp500 cp720 cp737 cp775
cp850 cp852 cp855 cp856 cp857 cp858 cp860 cp861 cp862 cp863 cp864
cp865 cp866 cp869 cp874 cp875 cp932 cp949 cp950 cp1006 cp1026 cp1125
cp1140 cp1250 cp1251 cp1252 cp1253 cp1254 cp1255 cp1256 cp1257 cp1258
cp65001 euc_jp euc_jis_2004 euc_jisx0213 euc_kr gb2312 gbk gb18030 hz
iso2022_jp iso2022_jp_1 iso2022_jp_2 iso2022_jp_2004 iso2022_jp_3
iso2022_jp_ext iso2022_kr latin_1 iso8859_2 iso8859_3 iso8859_4
iso8859_5 iso8859_6 iso8859_7 iso8859_8 iso8859_9 iso8859_10
iso8859_11 iso8859_13 iso8859_14 iso8859_15 iso8859_16 johab koi8_r
koi8_t koi8_u kz1048 mac_cyrillic mac_greek mac_iceland mac_latin2
mac_roman mac_turkish ptcp154 shift_jis shift_jis_2004 shift_jisx0213
utf_32 utf_32_be utf_32_le utf_16 utf_16_be utf_16_le utf_7 utf_8
utf_8_sig

使用的测试代码如下:

import socket
import gzip
s = socket.socket()
#Connecting using telnet
s.connect((HOST,23))
a = s.recv(1000)
问题原因

这串字节不属于可转码为可读文本的业务内容,是Telnet协议内置的选项协商指令帧,无法通过常规文本编码解码。
Telnet协议规定所有控制指令均以0xff(即字节\xff,简称IAC,全称Interpret As Command,意为"后续内容按命令解析")为起始标识,后跟1字节指令操作码、1字节选项码。收到的字节可拆分为4条独立协商指令:

  • \xff\xfb\x01:IAC WILL ECHO,服务端通知客户端将自行开启输入回显
  • \xff\xfb\x03:IAC WILL SUPPRESS-GO-AHEAD,服务端通知客户端将开启抑制go-ahead信号模式
  • \xff\xfd\x18:IAC DO TERMINAL-TYPE,服务端要求客户端上报自身终端类型
  • \xff\xfd\x1f:IAC DO NAWS,服务端要求客户端上报终端窗口尺寸
    其中操作码\xfb对应WILL(本端将启用指定选项),\xfd对应DO(要求对端启用指定选项)。
解决方法

根据实现需求二选一即可:

  • 方案1:直接使用Python标准库内置的telnetlib模块,无需手动处理socket层的协议协商逻辑,模块已封装完整的Telnet协商、数据收发、编解码能力,示例代码:
import telnetlib

# 替换为实际的Telnet服务地址
tn = telnetlib.Telnet(HOST, port=23, timeout=10)
# 如需登录可匹配提示后发送账号密码,例:
# tn.read_until(b"login: ")
# tn.write(b"your_username\n")
# tn.read_until(b"Password: ")
# tn.write(b"your_password\n")
# 读取服务端返回的可读文本
content = tn.read_very_eager().decode("utf-8", errors="ignore")
print(content)
  • 方案2:如果必须使用原生socket自行实现,需要先编写逻辑过滤、响应所有Telnet协商指令,将剥离控制指令后的纯文本内容再按对应编码解码,基础协商处理逻辑示例:
import socket

def handle_telnet_negotiation(sock):
    # 循环处理当前缓冲区所有协商指令
    while True:
        first_byte = sock.recv(1)
        if first_byte != b'\xff':
            # 非指令起始字节,拼接剩余接收内容返回
            return first_byte + sock.recv(999)
        # 读取操作码和选项码
        cmd = sock.recv(1)
        opt = sock.recv(1)
        # 默认响应逻辑:拒绝所有未显式支持的选项,避免协商死循环
        # 收到WILL/WONT时响应DONT,收到DO/DONT时响应WONT
        if cmd in (b'\xfb', b'\xfc'):
            sock.send(b'\xff\xfe' + opt)
        elif cmd in (b'\xfd', b'\xfe'):
            sock.send(b'\xff\xfc' + opt)

s = socket.socket()
s.connect((HOST, 23))
# 处理协商拿到纯文本数据
raw_text_bytes = handle_telnet_negotiation(s)
# 按服务端实际编码解码即可,多数Telnet服务使用utf-8或latin-1
readable_text = raw_text_bytes.decode("utf-8", errors="ignore")
print(readable_text)

内容的提问来源于stack exchange,提问作者smo zain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 11:45:35