Я пытаюсь выполнить программный сеанс telnet в Java. Я использую commons-net
TelnetClient
, но я также экспериментировал с прямым сокетом. В любом случае у меня такая же проблема.Java telnet login: после загрузки имени пользователя
Я прочитал «login:», а затем отправьте имя пользователя, а затем CRLF. Тогда ничего, никакие другие данные не читаются или не написаны сервером.
Сервер telnet находится на встроенном устройстве (принтер Star), поэтому мне интересно, есть ли какие-то особые параметры, которые я не настраиваю, или которые не поддерживаются классом commons-net
TelnetClient
.
Я могу использовать Linux telnet
без проблем, и я могу запустить свой код на сервере telnet в OSX, и он отлично работает.
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();
}
}
}
}
вот Wireshark PCAP провалившегося программной сессии https://drive.google.com/file/d/0B5iST80rpTN9c1RsRTNFaE5GZHM/view?usp=sharing
вот PCAP из успешного терминала (Linux телнет клиент) сессии https://drive.google.com/file/d/0B5iST80rpTN9bDZFOHhkSHlPSE0/view?usp=sharing
Я вижу, клиент Linux посылает «будет аутентифицировать», где мой код не делает. Я бы попробовал, если бы мог выяснить, как получить TelnetClient
для отправки таких команд.
Можете ли вы показать нам какой-нибудь код? – Thomas
Попытка не делать беспорядок сообщения. Я вставил код верхнего уровня. Обратите внимание, что я тестировал это на простом эхо-сервере, который я написал, и он работает, поэтому я считаю, что нет никаких проблем с кодом чтения/записи. –
Проверьте, что устройство отправляет с помощью реального клиента Telnet. Может быть, например, нет пробела после 'password:'. NB вам нужно найти 'Socket.setSoTimeout()'.Вам не нужны все эти потоки, блокировки и ожидания. – EJP