我试图用Java执行程序化的telnet会话。我使用commons-net
TelnetClient
,但我也尝试过直接套接字。无论哪种情况,我都有同样的问题。
我读到"登录:",然后发送用户名,后跟CRLF。什么都没有,没有其他数据被读取或由服务器写入。
telnet服务器位于嵌入式设备(Star打印机)上,所以我想知道是否需要一些特殊的选项,我没有设置,或者不支持commons-net
TelnetClient
上课。
我可以毫无问题地使用Linux telnet
,我可以在OSX中针对telnet服务器运行我的代码,它运行正常。
TelnetClient client = new TelnetClient();
client.registerNotifHandler(new TelnetNotificationHandler() {
@Override
public void receivedNegotiation(int negotiation_code, int option_code) {
ALog.i(this, "negotiation code: %d, option code: %d", negotiation_code, option_code);
}
});
try {
client.addOptionHandler(new TerminalTypeOptionHandler("VT100", false, false, true, false));
client.addOptionHandler(new SuppressGAOptionHandler(true, false, true, false));
client.addOptionHandler(new EchoOptionHandler(true, true, true, true));
} catch (InvalidTelnetOptionException e) {
e.printStackTrace();
}
try {
FileOutputStream fos = new FileOutputStream("/sdcard/spy.out");
client.registerSpyStream(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
InputStream in = null;
PrintWriter out = null;
String ip = getIpAddress(p);
ALog.i(this, "connecting to: %s", ip);
try {
client.connect(ip);
in = client.getInputStream();
out = new PrintWriter(client.getOutputStream(), true);
if (!expect(in, "login: ", 5000)) {
return;
}
if (!send(out, "root")) {
return;
}
if (!expect(in, "password: ", 5000)) {
return;
}
if (!send(out, "password")) {
return;
}
这里是expect()
和send()
方法,
protected boolean expect(InputStream in, String s, long timeout) {
ALog.i(this, "expecting: %s", s);
final AtomicBoolean lock = new AtomicBoolean(false);
final ExpectThread t = new ExpectThread(in, s, lock, timeout);
t.start();
synchronized (lock) {
try {
lock.wait(timeout);
} catch (InterruptedException e) {
}
}
t.interrupt();
return lock.get();
}
protected boolean send(PrintWriter out, String s) {
out.println(s);
out.flush();
ALog.i(this, "sent: %s", s);
return true;
}
这里是ExpectThread
,
private class ExpectThread extends Thread {
private final InputStream in;
private final String expected;
private final AtomicBoolean lock;
private final long start;
private final long timeout;
ExpectThread(InputStream in, String expected, AtomicBoolean lock, long timeout) {
this.in = in;
this.expected = expected.toLowerCase();
this.lock = lock;
this.timeout = timeout;
this.start = System.currentTimeMillis();
}
@Override
public void run() {
final StringBuilder b = new StringBuilder();
final byte[] buffer = new byte[1024];
int c;
try {
while (!isInterrupted() && System.currentTimeMillis() < start + timeout) {
ALog.i(this, "starting read ...");
while ((c = in.read(buffer)) != -1) {
String s = new String(buffer, 0, c);
b.append(s.toLowerCase());
ALog.i(this, "read string: %s, buffer: %s", s, b.toString());
if (b.toString().contains(expected)) {
ALog.i(this, "found expected");
lock.set(true);
return;
}
}
ALog.i(this, "waiting for read ...");
SystemClock.sleep(1000);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
synchronized (lock) {
lock.notifyAll();
}
}
}
}
这是FAILED程序会议的wirehark pcap, https://drive.google.com/file/d/0B5iST80rpTN9c1RsRTNFaE5GZHM/view?usp=sharing
这是一个成功的终端(linux telnet客户端)会话的pcap, https://drive.google.com/file/d/0B5iST80rpTN9bDZFOHhkSHlPSE0/view?usp=sharing
我看到Linux客户端发送了一个&#34; WILL AUTHENTICATE&#34;,我的代码没有。如果我能弄明白如何让TelnetClient
发送此类命令,我会尝试一下。
答案 0 :(得分:2)
您必须明确发送\r\n
,而不是println()
。它必须正是这样,而不是系统上println()
所做的任何事情。
我还怀疑你的expect()
方法可能正在提前阅读。它应该一次读取一个字节或一个字符,以确保不会发生这种情况。请尝试使用套接字读取超时而不是Megillah的线程和锁定并等待:
protected boolean expect(Socket socket, InputStream in, String expected, long timeout) throws IOException {
ALog.i(this, "expecting: %s", s);
long endTime = System.currentTimeMillis() + timeout;
byte[] buffer = new byte[8192];
StringBuffer b = new StringBuffer();
try
{
while (System.currentTimeMillis() < endTime)
{
socket.setSoTimeout((int)(endTime - System.currentTimeMillis()));
ALog.i(this, "starting read ...");
int c = in.read();
if (c == -1)
{
return false;
}
ALog.i(this, "read string: %s, buffer: %s", s, b.toString());
b.append(Character.valueOf((char)c));
if (b.toString().toLowerCase().contains(expected))
{
ALog.i(this, "found expected");
return true;
}
}
return false;
}
catch (SocketTimeoutException exc)
{
return false;
}
}
E&安培; OE
答案 1 :(得分:0)
回答我自己的问题......
正如我所怀疑的那样,这个特定服务器的telnet协商存在问题。我不得不使用一个非常具体的echo选项处理程序,
client.addOptionHandler(new EchoOptionHandler(false, false, false, true));
这意味着接受服务器正在发送的DO ECHO。我通过比较非工作会话和工作会话之间的telnet DO / WILL协商来发现这种差异。