通过telnet发送数据而无需按Enter键
我最近开始搞乱Java套接字和telnet ……
我希望用户能够连接到服务器,只需键入一个字母并将其发送到服务器,而无需按Enter键发送它。 我确定服务器没有办法设置它,但也许telnet有一个参数或什么可以允许这个?
也许如果我让用户在运行telnet之前键入stty cbreak
或stty raw
,这可行吗? (仅限UNIX,我知道!)
如果我可以通过telnet来执行此操作,那么我将不得不为此function编写一个特殊的客户端…
您应该可以通过telnet选项协商来执行此操作。 协议默认为半双工模式,并且至少对于交互式会话,服务器应协商suppress going ahead选项和echo选项 。
在最小的时候你可以在会话开始时吐出ff fb 01
ff fb 03
(会回显,会抑制 – 反超),然后用ff fb 01
回复任何ff fd 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();
实际上服务器有一种方法可以请求:它叫做telnet选项协商 。 通常,当您在其他端口上使用端口23和“cooked”(或“line”)模式时, telnet
将默认以“原始”模式配置本地tty。 行模式是您进行简约本地编辑的地方,当您点击返回时会发送数据。
禁用linemode后,您可以单独配置本地echo等内容。
编辑:我认为合理的顺序是:
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
,您可以检测并过滤输入流。
您需要查看telnet客户端的文档(例如手册页)。
例如,我的(Linux上的krb5-1.6 telnet实现)有一个mode character
命令,它关闭本地线路缓冲并立即发送大多数字符。
编辑:
禁用某些其他客户端(例如PuTTY)中的本地行编辑具有相同的结果。 PuTTY还具有可能有用的raw
连接模式。
请注意,如果您不介意在服务器上实现TELNET协议的某些部分,您还可以远程禁用本地线路编辑(LINEMODE TELNET选项)。
如果你不关心交互性,你也可以使用netcat:
echo -n X | nc host 7777
不幸的是,在许多系统(例如我的)上,netcat使用线路缓冲的I / O.
我建议使用netcat用于此目的。 它可以像即时信使一样,无需按Enter键。 搜索netcat教程会返回大量video。