我最近开始尝试使用Java sockets和telnet...
我希望用户能够连接到服务器,只需输入一个字母并将其发送到服务器,而无需按回车键发送。我确信服务器没有办法设置这个,但也许telnet有一个参数或其他东西可以实现这个?
也许如果我让用户在运行telnet之前输入stty cbreak
或stty raw
,这样会起作用吗?(仅适用于UNIX系统!)
如果我能让telnet实现这个功能,那么就不必为此编写特殊的客户端程序...
实际上,服务器确实有一种请求方式:它被称为telnet选项协商。通常情况下,telnet
会默认在使用23号端口时将本地tty配置为“原始”模式,在其他端口上则是“熟练”(或“行”)模式。行模式是指您拥有最简单的本地编辑功能,并且在按下回车键时发送数据。
一旦禁用了行模式,您就可以分别配置诸如本地回显之类的内容。
编辑:我认为一个合理的顺序应该是:
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)可用,然后将linemode LM_MODE
设置为0
(我认为这是告诉客户端不要进行任何本地编辑的正确方式)。最后,它说WILL ECHO
表示服务器将回显(因此客户端不会回显)。
客户端(如果支持telnet协商)将回复类似于IAC blah blah
或“引用”的序列,如IAC SB ... IAC SE
,您可以检测并过滤输入流中的这些序列。
最起码,您可以在会话开始时输出ff fb 01
ff fb 03
(将回显,将抑制前进),然后回复任何ff fd 01
(做回显)用ff fb 01
(将回显)进行回复,回复任何ff fd 03
(做抑制前进)的请求用ff fb 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();
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 = new PrintStream(conn.getOutputStream());
和 rawout = new OutputStreamWriter(conn.getOutputStream(), "ISO-8859-1");
然后,你可以使用 rawout.write((char)0xff);
发送单个255字节,但对于其他所有内容,可以使用 out.print("whatever \u2588");
。 - eater要配置telnet在不按回车键的情况下发送数据,您应该禁用行模式选项。这可以通过mode telnet子命令来完成:
将其设置为no line-mode将禁用行模式。
telnet> mode character
这可以实现逐个输入字符的模式。
echo -n X | nc host 7777
很不幸,在许多系统(包括我的)中,netcat使用的是行缓冲的I/O。
我的建议是使用netcat来实现这个目的。它可以像即时通讯一样运行,而不需要按Enter键。搜索netcat教程可以获得大量视频。