【问题标题】:Python reading until null character from TelnetPython 从 Telnet 读取直到空字符
【发布时间】:2014-11-25 23:36:04
【问题描述】:

我正在远程登录到我的服务器,它通过消息回复我,并且在每条消息的末尾附加了无法读取的 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 字符在那里:

【问题讨论】:

    标签: python telnet telnetlib null-character


    【解决方案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 然后依次由例如调用。读取_直到

    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 位代码。显示设备,简称 to 作为 RFC 中的打印机,只需要显示标准 打印由 7 位代码表示的 ASCII 字符并识别 并处理某些控制代码。 7位字符是 作为 8 位字节传输,最高有效位设置为零。 行尾以回车符 (CR) 的形式传输,后跟 换行(LF)。如果要传输实际的回车, 这作为回车后跟 NUL(所有位 零)字符。

    Name     Code   Decimal Value   
    Function NULL   NUL 0   No operation
    

    【讨论】:

      【解决方案2】:

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

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

      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
      

      这解决了我的问题。

      【讨论】:

        猜你喜欢
        • 2021-02-23
        • 1970-01-01
        • 1970-01-01
        • 2015-03-11
        • 2014-05-09
        • 2014-11-10
        • 1970-01-01
        • 1970-01-01
        • 2011-10-29
        相关资源
        最近更新 更多