ниже ссылка является примером Telnet Apache commonsnet, она имитирует пользователя с помощью клиента telnet (введите команду telnet и получите вывод), один поток читает поток, а другой поток пишет поток.
http://www.docjar.com/html/api/examples/weatherTelnet.java.html
Я изменяю эту программу, пользователь может войти на сервер telnet и ввести команду, но никогда не выходить из системы. примерно каждые 15 секунд пользователь вводит команду, а сервер выдает ему вывод. я использую другой поток, чтобы скопировать выходные данные сервера в локальный файл, но программа может работать, но это вызовет серьезную утечку памяти, примерно через несколько часов программа закроется из-за OutofMemoryException, используя инструмент дампа памяти кучи Java, я могу увидеть корень причина - char [] , которая определенно вызывается во время потока копирования.
Может ли кто-нибудь помочь мне указать, где проблема и как ее исправить? Большое спасибо.
public static final void readWrite( final InputStream remoteInput, final OutputStream remoteOutput,
final String address ) throws FileNotFoundException, InterruptedException
{
Thread reader = null;
Thread writer = null;
final String[] commands = new String[]{ "username\n", "password\n", "command\n" };
reader = new Thread("reader")
{
@SuppressWarnings( "null" )
@Override
public void run()
{
String currentCommand = null;
try
{
int i = 0;
while( !interrupted() )
{
if( i >= 3 )
currentCommand = "command\n";
else
currentCommand = commands[i++];
remoteOutput.write( currentCommand.getBytes() );
remoteOutput.flush();
sleep( 15000 );
}
}
catch( IOException e )
{
e.printStackTrace();
this.interrupt();
}
catch( InterruptedException e )
{
this.interrupt();
}
}
};
writer = new Thread("writer" )
{
@Override
public void run()
{
try
{
while( !isInterrupted() )
{
FileOutputStream fos = new FileOutputStream( "logfile" );
copyStream( remoteInput, fos, 1024, false );
fos.close();
sleep( 10000 );
}
}
catch( IOException e )
{
this.interrupt();
}
catch( InterruptedException e )
{
this.interrupt();
}
}
};
writer.setPriority( Thread.currentThread().getPriority() + 1 );
}
reader.start();
Thread.sleep( 2000 );
writer.start();
Thread.currentThread().join();
}
public static final long copyStream( InputStream source, OutputStream dest, int bufferSize, boolean flush )
throws CopyStreamException
{
int bytes;
long total;
byte[] buffer;
buffer = new byte[ bufferSize ];
total = 0;
try
{
while( ( bytes = source.read( buffer ) ) != -1 )
{
// Technically, some read(byte[]) methods may return 0 and we cannot
// accept that as an indication of EOF.
if( bytes == 13 )
{
dest.flush();
break;
}
if( bytes == 0 )
{
bytes = source.read();
if( bytes < 0 )
break;
dest.write( bytes );
if( flush )
dest.flush();
++total;
continue;
}
dest.write( buffer, 0, bytes );
if( flush )
dest.flush();
total += bytes;
}
}
catch( IOException e )
{
throw new CopyStreamException( "IOException caught while copying.", total, e );
}
return total;
}
Область комментариев слишком ограничена, пожалуйста, дайте мне напечатать ее здесь.
Целое приложение будет существовать до тех пор, пока не выйдет последний поток, не являющийся демоном.
да, я должен установить один из потоковых демонов без использования основного потока join (), верно?
Вам не нужно устанавливать приоритеты, они обычно не делают то, что вы думаете.
OK
Нет смысла прерывать поток, который собирается вернуться / завершить.
Да, следует удалить это Interrupt();
это нонсенс.
Зачем вам сбрасывать данные всякий раз, когда вы читаете ровно 13 байтов?
Ну, это плохой дизайн из-за моего реального спроса, но это будет другой темой, см. Позже об этом.
Ваши данные длины 0 не будут получены для блокирующего соединения, но если это произойдет, ваша обработка будет неправильной, и вам будет лучше без нее.
Ну, на самом деле этот метод скопирован из сети Apache Commons, см. Здесь: org. Apache. Commons. Net. Io. Util. Copystream(... )
CopyStream копирует данные до тех пор, пока поток не закончится, однако у вас есть это в цикле, что означает, что через 10 секунд вы урежете файл и замените его без данных (так как поток все еще закрыт, и вы не добавить файл журнала)
Да, это то, что мне нужно, мне нужен только последний вывод команды, предыдущий не имеет для меня значения, если я не усекаю файл, скоро файл станет больше и больше.
Ваш «читатель» записывает данные, он ничего не читает. Ваша ветка "писатель" читает и пишет.
Да, может быть, не очень хорошее имя, я поменяю его позже.
Вы используете Thread напрямую, что считается плохой практикой. Вы должны использовать Runnable и обернуть его потоком или использовать ExecutorService
Да, я изменю это позже.
Вы ловите несколько исключений, но не распечатываете их. Смело полагать, что вам не нужно знать, когда они брошены, поскольку ваша нить может умереть молча, и вы не будете знать, почему.
Да, я изменю его позже и у меня будут логи.
Я предполагаю, что CopyStreamException является Исключением, и в этом случае вы столкнулись с проблемой создания хорошего исключения, чтобы обернуть IOException, которое вы позже выбросите.
Вам не нужно спать между началом чтения и записи.
Да, я так думаю.
Поскольку ваш текущий поток просто ожидает двух других потоков, вы можете использовать текущий поток, чтобы написать «читатель», и иметь только один поток фоновой регистрации.
Да, только для автономного приложения, фактически этот фрагмент кода извлекается из веб-приложения (на стороне сервера), основной поток выполняет другую работу, я надеюсь, что два созданных мной потока никогда не умрут (продолжайте работу, когда веб-сервер работает)
Метод не вызывает исключение FileNotFoundException.
Выдает, см. Объявление внешнего метода.
Вы рассчитываете общее количество скопированных данных, но они никогда не используются.
Да, следует удалить.
Для копирования потока я предлагаю вам использовать IOUtils. Копировать (InputStream, OutputStream)
Я использовал раньше, однако это не отвечало моим потребностям: оно будет постоянно блокироваться, и вскоре размер файла журнала станет слишком большим, поэтому мне придется использовать пользовательский.
Зачем читать 13 байт и выходить?
Конечно, это магическое число. Я обнаружил, что если 13 байтов прочитано, то оно достигает конца вывода. Очевидно, что это плохой дизайн, не могли бы вы помочь мне найти более хороший способ?
Когда прежний поток вводит команду, сервер возвращает около 300 КБ контента.
Мне нужен метод, который может определить конец вывода на сервер, но я не могу понять это, потому что while( ( bytes = source. Read( buffer ) )!= -1 )
только что заблокирован!