通过 telnet 发送数据而不按回车键
Posted
技术标签:
【中文标题】通过 telnet 发送数据而不按回车键【英文标题】:Send data over telnet without pressing enter 【发布时间】:2011-05-30 18:16:02 【问题描述】:我最近开始使用 Java 套接字和 telnet...
我希望用户能够连接到服务器,只需键入一个字母并将其发送到服务器,而无需按 Enter 发送它。我确定服务器没有办法设置它,但也许 telnet 有一个参数或其他东西可以允许这样做?
也许如果我让用户在运行 telnet 之前输入 stty cbreak
或 stty raw
,这会起作用吗? (仅限 UNIX,我知道!)
如果我可以使用 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 option 和echo 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 教程会返回大量视频。
【讨论】:
我认为这只是世界在变化,现在我们有视频告诉我们如何使用基于控制台的程序。我可以欣赏其中的幽默 ;-)以上是关于通过 telnet 发送数据而不按回车键的主要内容,如果未能解决你的问题,请参考以下文章