【问题标题】:Send data over telnet without pressing enter通过 telnet 发送数据而不按回车键
【发布时间】:2011-05-30 18:16:02
【问题描述】:

我最近开始使用 Java 套接字和 telnet...

我希望用户能够连接到服务器,只需键入一个字母并将其发送到服务器,而无需按 Enter 发送它。我确定服务器没有办法设置它,但也许 telnet 有一个参数或其他东西可以允许这样做?

也许如果我让用户在运行 telnet 之前输入 stty cbreakstty raw,这会起作用吗? (仅限 UNIX,我知道!)

如果我可以使用 telnet 来执行此操作,那么我就不必为此功能编写一个特殊的客户端...

【问题讨论】:

    标签: java sockets terminal telnet


    【解决方案1】:

    实际上一种服务器请求此的方法:它称为telnet option negotiation。通常telnet 在您使用端口 23 和在其他端口上使用“cooked”(或“line”)模式时默认将本地 tty 配置为“raw”模式。行模式是您进行简约的本地编辑并在您点击返回时发送数据的地方。

    禁用线路模式后,您可以单独配置本地回显等内容。

    编辑:我认为合理的顺序是:

    255, 253, 34,  /* IAC DO LINEMODE */
    255, 250, 34, 1, 0, 255, 240 /* IAC SB LINEMODE MODE 0 IAC SE */
    255, 251, 1    /* IAC WILL ECHO */
    

    这会启用TELOPT_LINEMODE (34),然后将线模式LM_MODE 设置为0(我认为这是告诉客户端不要进行任何本地编辑的正确方法)。最后它说WILL ECHO 表明服务器会回显(所以客户端不会)。

    客户端(如果它支持 telnet 协商)将回复像 IAC blah blah 这样的序列或像 IAC SB ... IAC SE 这样的“引用”序列,您可以检测并从输入流中过滤掉这些序列。

    【讨论】:

    • 我在哪里以及如何发送这些选项?
    • +1 这看起来是正确的答案。请参阅我的更新答案以了解如何操作。
    【解决方案2】:

    您应该能够通过 telnet 选项协商来执行此操作。 协议默认为半双工模式,至少对于交互式会话,服务器应协商suppress go ahead optionecho option

    在会话开始时,您至少可以吐出ff fb 01 ff fb 03(将回显,将抑制继续前进),然后回复任何ff fd 01(回显)使用ff fb 01(将回显)并使用ff fb 03(将抑制-继续)回复任何ff fd 03(抑制前进)。

    编辑添加 Ben Jackson 提到的线路模式协商是一个更好的答案。对于在 23 以外的端口上连接的大多数客户端来说,抑制反冲是不够的。

    但是我认为您遇到的另一个问题是 Java 正在发送 Unicode 字符。例如,当您说 (char)0xff 时,Java 假定您指的是 UTF-16 字符 U+00ff,即 ÿ。它可能使用 UTF-8 编码通过套接字发送它,因此 telnet 客户端看到两个字节:c3 bf,它传递并显示为ÿ

    您可以做的是明确告诉 Java 使用 ISO-8859-1 编码。例如,您以前可能做过这样的事情:

    out = new PrintStream(connection.getOutputStream());
    out.print((char)0xff);  // sends 0xc3 0xbf
    out.print((char)0xfb);  // sends 0xc3 0xbb
    out.print((char)0x01);  // sends 0x01
    out.flush();
    

    相反,您可以使用 OutputStreamWriter 来指定您想要的编码:

    out = new OutputStreamWriter(connection.getOutputStream(), "ISO-8859-1");
    out.write((char)0xff);  // sends 0xff
    out.write((char)0xfb);  // sends 0xfb
    out.write((char)0x01);  // sends 0x01
    out.flush();
    

    【讨论】:

    • 我不太明白将这些选项代码发送到哪里。我正在尝试在连接时将这些字符发送给客户端:out.print((char)0xff); out.print((char)0xfb); out.print((char)0x01); out.print((char)0xff); out.print((char)0xfb); out.print((char)0x03); out.flush();但这只是打印出ÿûÿû^
    • 我需要降级吗?
    • 使用 ISO-8859-1 而不是 UTF-8 使我无法使用扩展的 ASCII 字符(128 到 255)。我之前将它们作为 unicode 字符串(即 \u2588 表示 219)发送,这显然不再有效。相反,我尝试将它们作为字符发送,例如仅 219,它只是将它们打印为 � 字符。有什么办法可以解决这个问题?
    • 我认为您可以同时使用 PrintStream 和 OutputStreamWriter。调用 out = new PrintStream(conn.getOutputStream()); AND rawout = new OutputStreamWriter(conn.getOutputStream(), "ISO-8859-1"); 然后你可以使用 rawout.write((char)0xff); 发送单个 255 字节,但 out.print("whatever \u2588"); 发送其他所有内容。
    【解决方案3】:

    您需要查看 telnet 客户端的文档(例如手册页)。

    例如我的(Linux 上的 krb5-1.6 telnet 实现)有一个 mode character 命令,它关闭本地行缓冲并立即发送大部分字符。

    编辑:

    在其他一些客户端(例如 PuTTY)中禁用本地行编辑具有相同的结果。 PuTTY 还有一个可能有用的raw 连接模式。

    请注意,如果您不介意在服务器上实现 TELNET 协议的某些部分,您还可以远程禁用本地行编辑(LINEMODE TELNET 选项)。

    如果您不关心交互性,您也可以使用 netcat:

    echo -n X | nc host 7777
    

    不幸的是,在许多系统(例如我的)上,netcat 使用行缓冲 I/O。

    【讨论】:

      【解决方案4】:

      要配置 telnet 以在不按 Enter 的情况下发送数据,您应该禁用线路模式选项。这是通过 mode telnet 子命令完成的:

      telnet> mode character
      

      这会启用角色一次模式。

      【讨论】:

        【解决方案5】:

        我的建议是为此目的使用netcat。它可以像即时通讯工具一样运行,无需按 Enter。搜索 netcat 教程会返回大量视频。

        【讨论】:

        • 我认为这只是世界在变化,现在我们有视频告诉我们如何使用基于控制台的程序。我可以欣赏其中的幽默 ;-)
        猜你喜欢
        • 2011-05-08
        • 2017-10-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-15
        • 1970-01-01
        • 2014-04-11
        • 2014-09-01
        相关资源
        最近更新 更多