1

我正在远程登录到我的服务器,该服务器用消息回答我,并且在每条消息的末尾附加了无法读取的 hex00(空字符)。我尝试通过搜索,但似乎无法使其工作,一个简单的例子:

from telnetlib import Telnet
connection = Telnet('localhost', 5001)
connection.write('aa\n')
connection.read_eager()

这将返回一个输出:

'Fail - Command aa not found.\n\r'

而应该有这样的东西:

'Fail - Command aa not found.\n\r\0'

有没有办法得到这个字符串字符的结尾?如果故意遗漏字符,我可以获取字节作为输出吗?

00 字符在那里:

tcpdump

4

2 回答 2

2

在尝试使用 telnet 从 RS232-TCP/IP 转换器获取数据时,我偶然发现了同样的问题 - telnetlib 会抑制消息中的每个 0x00。正如 Fredrik Johansson 很好地回答的那样,这是 telnetlib 的实现方式。

一种解决方案是覆盖process_rawq()telnetlib 的 Telnet 类中不吃所有空字符的函数:

import telnetlib
from telnetlib import IAC, DO, DONT, WILL, WONT, SE, NOOPT

def _process_rawq(self):
    """Alteração da implementação desta função necessária pois telnetlib suprime 0x00 e \021 dos dados lidos
    """
    buf = ['', '']
    try:
        while self.rawq:
            c = self.rawq_getchar()
            if not self.iacseq:
#                if c == theNULL:
#                    continue
#                if c == "\021":
#                    continue
                if c != IAC:
                    buf[self.sb] = buf[self.sb] + c
                    continue
                else:
                    self.iacseq += c
            elif len(self.iacseq) == 1:
                # 'IAC: IAC CMD [OPTION only for WILL/WONT/DO/DONT]'
                if c in (DO, DONT, WILL, WONT):
                    self.iacseq += c
                    continue

                self.iacseq = ''
                if c == IAC:
                    buf[self.sb] = buf[self.sb] + c
                else:
                    if c == SB: # SB ... SE start.
                        self.sb = 1
                        self.sbdataq = ''
                    elif c == SE:
                        self.sb = 0
                        self.sbdataq = self.sbdataq + buf[1]
                        buf[1] = ''
                    if self.option_callback:
                        # Callback is supposed to look into
                        # the sbdataq
                        self.option_callback(self.sock, c, NOOPT)
                    else:
                        # We can't offer automatic processing of
                        # suboptions. Alas, we should not get any
                        # unless we did a WILL/DO before.
                        self.msg('IAC %d not recognized' % ord(c))
            elif len(self.iacseq) == 2:
                cmd = self.iacseq[1]
                self.iacseq = ''
                opt = c
                if cmd in (DO, DONT):
                    self.msg('IAC %s %d',
                        cmd == DO and 'DO' or 'DONT', ord(opt))
                    if self.option_callback:
                        self.option_callback(self.sock, cmd, opt)
                    else:
                        self.sock.sendall(IAC + WONT + opt)
                elif cmd in (WILL, WONT):
                    self.msg('IAC %s %d',
                        cmd == WILL and 'WILL' or 'WONT', ord(opt))
                    if self.option_callback:
                        self.option_callback(self.sock, cmd, opt)
                    else:
                        self.sock.sendall(IAC + DONT + opt)
    except EOFError: # raised by self.rawq_getchar()
        self.iacseq = '' # Reset on EOF
        self.sb = 0
        pass
    self.cookedq = self.cookedq + buf[0]
    self.sbdataq = self.sbdataq + buf[1]
telnetlib.Telnet.process_rawq = _process_rawq

然后覆盖 Telnet 类的方法:

telnetlib.Telnet.process_rawq = _process_rawq

这为我解决了这个问题。

于 2015-09-16T18:43:35.520 回答
1

这段代码(http://www.opensource.apple.com/source/python/python-3/python/Lib/telnetlib.py)似乎只是忽略了空字符。这真的是正确的行为吗?

def process_rawq(self):
    """Transfer from raw queue to cooked queue.

    Set self.eof when connection is closed.  Don't block unless in
    the midst of an IAC sequence.

    """
    buf = ''
    try:
        while self.rawq:
            c = self.rawq_getchar()
            if c == theNULL:
                continue
:
:

然后 process_rawq 依次由例如 read_until 调用

def read_until(self, match, timeout=None):
    """Read until a given string is encountered or until timeout.

    When no match is found, return whatever is available instead,
    possibly the empty string.  Raise EOFError if the connection
    is closed and no cooked data is available.

    """
    n = len(match)
    self.process_rawq()
    :
    :

我也想接收空字符。在我的特殊情况下,它标志着多行消息的结束。

所以答案似乎是在编写库代码时这是预期的行为。

FWIW https://support.microsoft.com/en-us/kb/231866状态:

使用 TCP/IP 建立通信并基于网络虚拟终端 (NVT)。在客户端,Telnet 程序负责将传入的 NVT 代码转换为客户端显示设备可以理解的代码,以及将客户端生成的键盘代码转换为传出的 NVT 代码。

NVT 对字符使用 7 位代码。显示设备,在 RFC 中称为打印机,只需要显示由 7 位代码表示的标准打印 ASCII 字符,并识别和处理某些控制代码。7 位字符作为 8 位字节传输,最高有效位设置为零。换行符以回车符 (CR) 后跟换行符 (LF) 的形式传输。如果要传输实际的回车,则将其传输为回车,后跟 NUL(所有位为零)字符。

Name     Code   Decimal Value   
Function NULL   NUL 0   No operation
于 2015-09-15T17:37:46.957 回答