Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как избежать запуска второй копии программы, Если прокрамма использует сокет по назна 
V
    Опции темы
Su_
Дата 12.1.2010, 00:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



Добрый день.. Есть задача,сделать так что бы при втором запуске java-приложение, оно блокировалось и перекидывало фокус на уже открытое .. 

Разделил на два этапа 1)НЕ допустить запуска второй копии 2)Перебросить фокус

1)Почитал в интернете и тут, нашел два способа, это занимать порт и лочить файл.Т.к я и так занимаю порт под нужные цели, первым вариантом пользоваться не хочется . 2 )Нашел в интернете такую реализацию:
Код

try {
    // Get a file channel for the file
    File file = new File("filename");
    FileChannel channel = new RandomAccessFile(file, "rw").getChannel();

    // Use the file channel to create a lock on the file.
    // This method blocks until it can retrieve the lock.
    FileLock lock = channel.lock();

    // Try acquiring the lock without blocking. This method returns
    // null or throws an exception if the file is already locked.
    try {
        lock = channel.tryLock();
    } catch (OverlappingFileLockException e) {
        // File is already locked in this thread or virtual machine
    }

    // Release the lock
    lock.release();

    // Close the file
    channel.close();
} catch (Exception e) {
}



НО что в винде что в линуксе,всё время пишет что файл(ТХТ) залочен,т.е уходит на исключение
Что тут не так?

2)Можно ли вообще сделать фокусировку на приложение программно?




--------------------
user posted image

PM MAIL WWW   Вверх
Su_
Дата 12.1.2010, 00:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



Первый вопрос решил)


--------------------
user posted image

PM MAIL WWW   Вверх
Su_
  Дата 12.1.2010, 02:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



По поводу первого пункта, может кому пригодится:
В начало программы:
Код

 accessTheLockedFile();
     if(number_of_copy==0)
     {
            try {
                   lock_file();
        }catch(IOException f)
        {
            System.out.println("error ini");
                 prints("Запущена вторая копия");
        }
     }else if(number_of_copy==1)
     {
         prints("Это ПРОГРАММА УЖЕ ЗАПУЩЕННА!,закройти приложение и откройте 'ALT+TAB' уже запущенную программу");
         System.exit(0);
     }
     if(block)
     {
         System.exit(0);
     }


методы 
Код

  public void lock_file() throws FileNotFoundException, IOException
    {
  RandomAccessFile file = null;
        FileLock fileLock = null;
        try
        {
         //    prints("1");
            file = new RandomAccessFile(PathtoLockFile, "rw");
          //     prints("2");
            FileChannel fileChannel = file.getChannel();
  // prints("3");
            fileLock = fileChannel.tryLock();
           //    prints("4");
            if (fileLock != null){
               prints("Приложение запущенно");
               number_of_copy=1;
              accessTheLockedFile();
            }
        }finally{
            if (fileLock != null){
             //    prints("5");
                 block=false;

            }
        }
    }

     static void accessTheLockedFile(){

        try{
            FileInputStream input = new FileInputStream(PathtoLockFile);
            int data = input.read();
            System.out.println(data);
        //    prints("ФАЙЛ РАЗБЛОКИРОВАН!");
            number_of_copy=0;
        }catch (Exception exception){
            exception.printStackTrace();
          //    prints("ФАЙЛ ЗАБЛОКИРОВАН!");
            number_of_copy=1;
        }
    }


Работает и в win и в lin, при чем: В винде блокирует файлы нормально, в Линуксе файл не блокирует , но повторно войти в 
Код

     if (fileLock != null){
             //    prints("5");
                 block=false;

            }

не может. Для этого еще есть проверка флага block. Почему не блокирует файл я так и не понял, но это работает.

Осталось разворачивать уже запущенное приложение вместо запуска ещё одной копии (lin) ???


--------------------
user posted image

PM MAIL WWW   Вверх
Su_
Дата 12.1.2010, 02:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



увы этот алгоритм дает сбой в Linux.. отсюда вопрос как заблокировать файл в linux?????????7


--------------------
user posted image

PM MAIL WWW   Вверх
dobrolub
Дата 12.1.2010, 02:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 385
Регистрация: 18.12.2009
Где: Vancouver, Canada

Репутация: 11
Всего: 16



Thread t = new Thread() {
  public void run() {
      new FileInputStream("zzz").getChannel().tryLock(); 
   }
};

t.start();
t.join(100);//даём 100 ms на захват лока.

try {
  t.interrupt();
} catch (Exception e) {
 //обработка 
}

Это сообщение отредактировал(а) dobrolub - 12.1.2010, 03:00
PM   Вверх
Su_
Дата 12.1.2010, 03:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



если это повесить на кнопку 
Код

    try {
            //chek_alarm();
    new FileInputStream("zzz").getChannel().tryLock();

    }catch(IOException f)
        {
          System.out.println("Не могу заблокировать");
        }
            //tcp_socket_busy=false;        // TODO add your handling code here:
    } 

вылетает на исключение ,при чем не на IOException


А вообще линукс поддерживает блокировку файлов?

Добавлено через 6 минут и 25 секунд
для запуска
Код


import java.io.FileInputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Admin
 */
public class NewClass {
Thread t = new Thread() {
  public void run() {
            try {
                new FileInputStream("zzz").getChannel().tryLock();
            } catch (IOException ex) {
                Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
            }
   }
};
NewClass() throws InterruptedException
{
t.start();
t.join(100);//даём 100 ms на захват лока.

try {
  t.interrupt();
} catch (Exception e) {
 //обработка
}
}

 public static void main(String[] args) throws InterruptedException
  {
     NewClass f=new NewClass();
  }
}



после запуска
Код

run:
Exception in thread "Thread-0" java.nio.channels.NonWritableChannelException
        at sun.nio.ch.FileChannelImpl.tryLock(FileChannelImpl.java:875)
        at java.nio.channels.FileChannel.tryLock(FileChannel.java:962)
        at NewClass$1.run(NewClass.java:20)
BUILD SUCCESSFUL (total time: 0 seconds)


Я не очень понимаю,почему в винде блокирует нормально,а в линуксе нет.?


--------------------
user posted image

PM MAIL WWW   Вверх
dobrolub
Дата 12.1.2010, 03:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 385
Регистрация: 18.12.2009
Где: Vancouver, Canada

Репутация: 11
Всего: 16



Возможно баг в JDK, но вроде с помощью exception всё можно отследить как я понял.
PM   Вверх
Su_
Дата 12.1.2010, 03:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



к сожалению нет. суть то основываться на блокировки файла , если залочен ,значит одна копия запущена, а так как в Linux он их не лочит, этого не сделать, походу придется на порт вешать.,хотя писали что это далеко не самое лучше решение! dobrolub  спасибо)


--------------------
user posted image

PM MAIL WWW   Вверх
dobrolub
Дата 12.1.2010, 03:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 385
Регистрация: 18.12.2009
Где: Vancouver, Canada

Репутация: 11
Всего: 16



так получается что не за что :(

слушай а что за JDK / Linux?
PM   Вверх
Su_
Дата 12.1.2010, 03:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



java-1.6.0-openJDK уже стояло на мое MandrivaFree2009. Я думаю тут различие идет по возможности lock/unlock по ОС а не по JDK


--------------------
user posted image

PM MAIL WWW   Вверх
dobrolub
Дата 12.1.2010, 04:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 385
Регистрация: 18.12.2009
Где: Vancouver, Canada

Репутация: 11
Всего: 16



на debian 5 с JDK от Sun.
java version "1.6.0_07"
Java™ SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot™ Client VM (build 10.0-b23, mixed mode, sharing)

код внизу отработал нормально.
Код

import java.io.*;
import java.nio.*;

public class T {
    public static void main(String[] args) throws Exception {
        System.out.println(new FileOutputStream("xxx").getChannel().tryLock());

        synchronized(T.class) {
            T.class.wait();
        }
    }
}


первый запуск:
Код

x@debian:/tmp$ java T
sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

второй - параллельный запуск
Код

x@debian:/tmp$ java T
null


Добавлено через 13 минут и 39 секунд
проверил с версией 1.5 - тоже работает. То есть возможно проблема в JDK

java version "1.5.0_16"
Java™ 2 Runtime Environment, Standard Edition (build 1.5.0_16-b02)
Java HotSpot™ Client VM (build 1.5.0_16-b02, mixed mode, sharing)



Это сообщение отредактировал(а) dobrolub - 12.1.2010, 04:27
PM   Вверх
Su_
Дата 12.1.2010, 04:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



ого Спасибо, это важно для меня ..поковыряюсь с JDK)

Добавлено через 9 минут и 5 секунд
Слушай у меня такой же вывод выдает теперь.. может я где то напортачил ,надо больше спать) Спасибо большое !


--------------------
user posted image

PM MAIL WWW   Вверх
Su_
Дата 12.1.2010, 05:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



токо не понял почему он в дальнейшем сбрасывает Lock , если в этом же потоке работать с файлами)


--------------------
user posted image

PM MAIL WWW   Вверх
dobrolub
Дата 12.1.2010, 05:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 385
Регистрация: 18.12.2009
Где: Vancouver, Canada

Репутация: 11
Всего: 16



я думаю что lock сбрасывается когда переменные выходят из области видимости и собираются мусорщиком. 
Лучше бы переменные связанные с этим локом положить в новую thread и добавить её kak shutdownHook

Runtime.getRuntime().addShutdownHook(new Thread() {
  public void run() {
    //освободить локи, закрыть выходные потоки.
  }
});



      
      

PM   Вверх
dobrolub
Дата 12.1.2010, 06:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 385
Регистрация: 18.12.2009
Где: Vancouver, Canada

Репутация: 11
Всего: 16



>1)Почитал в интернете и тут, нашел два способа, это занимать порт и лочить файл.Т.к я и так занимаю порт под нужные цели, первым вариантом пользоваться не хочется

Я про порт не понял, с ним железней, в общем-то, тем более он так и так должен выделиться системой.
PM   Вверх
Zefick
Дата 12.1.2010, 07:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 3.12.2009

Репутация: 1
Всего: 2



  Su_, я не понимаю, почему Вы отмели идею о занятии порта. Мне она пришла в голову сразу, как только я прочитал название темы (наверное, потому что в универе не так давно была лаба по сетевым приложениям на Java и что будет, если запустить два сервера я отлично помню). К тому же Вы говорите, что порт у вас и так занимается. Вот и замечательно - при второй попытке его занять выбросится исключение, которое надо ловить и передавать фокус в первую программу.

PM MAIL   Вверх
Su_
Дата 12.1.2010, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



Сейчас я её реализовал правда на другом порте.,т.к на основной не хочеться кидать, иногда в процессе работы (прием сообщений ) вылетает исключение в ожидание порта ,потом пересоздается. С лок-файлом наиболее красивое решение, не надо занимать сетевой порт ,и не должно висеть порт,что если на этот порт начнут спамить ,и он выкинеть исключение)


--------------------
user posted image

PM MAIL WWW   Вверх
Su_
Дата 12.1.2010, 13:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



а как передать фокус в первую программу?


--------------------
user posted image

PM MAIL WWW   Вверх
serger
Дата 12.1.2010, 13:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 19.6.2007
Где: Ижевск

Репутация: 1
Всего: 5



Грубо.
Занятие порта хорошая идея, до тех пор пока есть сеть.
В последнее время сеть, правда, уже почти везде...


--------------------
упс!
PM MAIL WWW Skype GTalk Jabber   Вверх
Su_
Дата 12.1.2010, 17:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



а как передать фокус в первую программу?

Добавлено через 1 минуту и 14 секунд
в смысле ГРубо? там мегафон интернет который иногда отваливается ..


--------------------
user posted image

PM MAIL WWW   Вверх
Su_
Дата 12.1.2010, 20:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



решил вопрос о восстановление фокуса,правда если через порт делать..

т.е. вешаю порт на сервер, если вылетает исключение шлю на этот же порт connect , а если на этом порту срабатывает accept то он делать

Код

setExtendedState(MAXIMIZED_BOTH);


т.е так :
Код

while(true)
      {
s = ss.accept();
prints("Восстановление окна");
setExtendedState(MAXIMIZED_BOTH);
    }
    }
    catch(Exception ioe)
    {
      //    block_multi_sender=false;
      System.out.println(ioe.toString());
      try
    {
      Socket s_block = new Socket();

      s_block.connect(new InetSocketAddress(myadress,Port2),200);
      }catch(Exception f)
    {

      }
      System.exit(0);
     //  prints("Принудительный сброс соединения");
     // prints("Данный порт уже занят!!!Закройте все приожения кроме одного и нажмите кнопку 'перезапустить TCP'.Попытка перезапустить ТСП автоматически...");
         // Закрываем соединение
     }




--------------------
user posted image

PM MAIL WWW   Вверх
dobrolub
Дата 12.1.2010, 21:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 385
Регистрация: 18.12.2009
Где: Vancouver, Canada

Репутация: 11
Всего: 16



хороший способ; другой, кросс-платформный, трудно найти я думаю.
PM   Вверх
Su_
Дата 13.1.2010, 02:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 386
Регистрация: 1.8.2007

Репутация: нет
Всего: нет



будем тестировать, Важна стабильность)Спасибо всем кто помогал, я думаю топик можно закрыть)


--------------------
user posted image

PM MAIL WWW   Вверх
Viroman
Дата 15.6.2010, 08:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 140
Регистрация: 28.7.2008

Репутация: нет
Всего: нет



http://forum.vingrad.ru/forum/topic-303234.html

В продолжение этой темы, модер поспешил закрыть даже до конца не поняв сути, не конкретно незапуск второй копии, а именно шаринг списка задач, общий блок памяти, или ещё чего нибудь быстрое.
Порты занимать уже проходили, не то, глупый вариант, и я о нём уже думал, но видимо больше хороших идей нет :(
PM MAIL   Вверх
Viroman
Дата 11.7.2010, 16:09 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 140
Регистрация: 28.7.2008

Репутация: нет
Всего: нет



Код

import java.io.*;
import java.nio.*;
public class T {
    public static void main(String[] args) throws Exception {
        System.out.println(new FileOutputStream("xxx").getChannel().tryLock());
        synchronized(T.class) {
            T.class.wait();
        }
    }
}

Кстати, просто обязан поблагодарить dobrolub за предоставленный код, работает на ура.
Только как я понял, дискуссия была по поводу нерабочести под линуском.
Так вот, если вдруг столкнётся кто то с этой проблемой вновь, есть одно огромное различие в плане использования этой фишки под виндой и линухом.
Дурость заключается в том, что при воспроизведении этого кода
 System.out.println(new FileOutputStream("xxx").getChannel().tryLock());
на винде файл лочится до конца воспроизведения всей джава машины!!! и работает как надо и ожидается, что так и будет работать, ведь никто лок программно не освобождает. Но на линухе это не работает, как ожидается!!! Фишка заключается в том, что если воспроизвести этот код
 System.out.println(new FileOutputStream("xxx").getChannel().tryLock());
то система залочит файл, а потом она его тут же разблокирует, к сожалению, и это и явилось подводным камнем и для меня, и похоже для топикстартера!!!
Дабы избежать этой проблемы в КОРНЕ, учтите на будущее,
запускайте выжеизложенный код как есть с синхронизацией и wait в отдельном потоке и тогда и файл лочится прекрасно и не разлочивается до конца воспроизведения машины, и работает и на винде, линухе, маке итп... Может кому то это поможет, чтобы на те же грабли не наступали..
PM MAIL   Вверх
koreyko
Дата 27.3.2013, 00:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 50
Регистрация: 20.4.2010

Репутация: нет
Всего: нет



Здравствуйте, уважаемые форумчане.

Решил не открывать новую тему, т.к. стоит та же задача - сворачивание приложения в трей и его восстановление из трея при попытке запуска второй копии приложения. Задачу блокировки второй копии решил с помощью лок-файла. Осталось передать фокус в запущенную первой копию. 

Я пробую сделать это через instance ID. Получаю и сохраняю ID в залоченный файл, при запуске второй копии - считываю. Теперь остался последний шаг: достучаться к уже запущенному инстансу через его ID и восстановить окно программы. 

Подскажите, пожалуйста, как это сделать?

Спасибо.
PM MAIL   Вверх
COVD
Дата 27.3.2013, 15:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Цитата

Теперь остался последний шаг: достучаться к уже запущенному инстансу через его ID и восстановить окно программы. 

Надо делать, как уже писали выше, все через порт. Приложение при запуске должно запускать сервер, который принимает сокетные соединения на любом свободном порту из заданного диапазона. Приложение должно провести поиск  других инстансев соединяясь поочередно к портам  из заданного диапазона. Если соединение успешно создано и пароль совпадает, значит два инстанса друг друга нашли и дальше могут обмениваться командами через сокетное соединение.
PM MAIL   Вверх
koreyko
Дата 27.3.2013, 15:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 50
Регистрация: 20.4.2010

Репутация: нет
Всего: нет



Спасибо, а где можно почитать об этом способе - через порт? Желательно с примерами. После прочтения ветки ясность не наступила, к сожалению.
PM MAIL   Вверх
COVD
Дата 27.3.2013, 17:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43




Примерно так. 
Запустите этот класс два раза. Когда вторая инстанс стартует, первая закрывается командой System.exit(0). Можно любое другое поведение реализовать.

Код

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

/**
 * On application start ShutdownServer runs one time task.
 * Task searches another application instances on local computer and send shutdown command
 * if discovered instance runs with the same userID value.
 *
 * @author
 */
public class ShutdownServer {
    private static String thisApplicationUserID;
    private static int portDefault = 25000;
    private static int portRange = 5;
    private static int readTimeout  = 2000;// 2 sec
    private static boolean daemon  = true;// false, if started from main()
    
    
    private static final String COMMAND_HELLO = "HELLO";
    private static final String COMMAND_SHUTDOWN = "SHUTDOWN";
    private static Thread serverSocketThread;

    
    public static void start(String userID){
        thisApplicationUserID = userID;                
        Thread t = new Thread(){
            public void run(){                
                discoverInstances(); 
                startServer();
            }
        };       
        t.start();       
    }      
        
    /**
     * Method starts thread listening connections on first found available port from range 25000 .. 25004     
     */
    private static void startServer() {
        int port = portDefault;
        for (int i = 0; i < portRange; i++) {        
            try {                
                final ServerSocket serverSocket = new ServerSocket(port);    
                serverSocketThread = new Thread(){
                    public void run(){
                        runServerSocket(serverSocket);
                    }
                };  
                serverSocketThread.setDaemon(daemon);
                serverSocketThread.start();
                break;
            } catch (IOException ex) {                
            }
            port++;
        }
    } 
    
    /**
     * Method runs socket accept loop.
     * On input command COMMAND_HELLO thread responds with thisApplicationUserID value.
     * On input command COMMAND_SHUTDOWN thread shutdowns this application.
     */    
    private static void runServerSocket(ServerSocket serverSocket) {
        try {
            System.out.println("ShutdownServer starts on port: " + serverSocket.getLocalPort());
            while (!Thread.currentThread().isInterrupted()) {
                Socket socket = null;
                try {
                    
                    socket = serverSocket.accept();                    
                    socket.setSoTimeout(readTimeout);
                   
                    String request = readLine(socket);                                            

                    if (request == null) {
//                        System.out.println("runServerSocket: null input");
                        continue;
                    }


                    int index = request.indexOf(":");
                    if (index == -1) {
//                        System.out.println("runServerSocket: wrong format");
                        continue;
                    }


                    int portSent = -1;
                    try {
                        portSent = Integer.parseInt(request.substring(0, index));
                    } catch (Exception e) {
                    }

                    if (portSent == -1) {
//                        System.out.println("runServerSocket: wrong port: " + request);
                        continue;
                    }

                    if (portSent != serverSocket.getLocalPort()) {
//                        System.out.println("runServerSocket: not equal to current port: " + portSent + " != " + serverSocket.getLocalPort());
                        continue;
                    }

                    String command = request.substring(index + 1);
                    System.out.println("command:"+command);
                    
                    if (command.equals(COMMAND_HELLO)) {//respond this userID to another application 
                        String response = String.valueOf(serverSocket.getLocalPort()) + ":" + thisApplicationUserID;
                        printLine(socket, response);
                    } else if (command.equals(COMMAND_SHUTDOWN)) {//shutdown this application by command from another application    
                        System.out.println("app exits");
                        System.exit(0);
                    } else {
//                        System.out.println("runServerSocket: unsupported command:" + command);
                    }



                } catch (Exception ex) {
                    System.out.println("ShutdownServer:" + ex);                    
                } finally {                    
                    close(socket);
                }
            }
        } finally {            
            close(serverSocket);            
        }        
    }
    
    private static void printLine(Socket socket, String str) throws IOException{
        PrintWriter pw = new PrintWriter(socket.getOutputStream()); 
        pw.println(str);
        pw.flush();        
//        System.out.println("printLine:"+str);
    }
    
    private static String readLine(Socket socket) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line = br.readLine();                      
//        System.out.println("readLine:"+line); 
        return line;
        
    }  
    
    private static void close(Object obj) {
        if (obj != null) {
            if (obj instanceof Socket) {
                try {
                    ((Socket) obj).close();
                } catch (IOException ex) {
                }
            }
            else
            if (obj instanceof ServerSocket) {
                try {
                    ((ServerSocket) obj).close();
                } catch (IOException ex) {
                }
            }                
        }
    }
    /**
     * Method perform open ports search on local computer in range 25000 .. 25004
     * If connection to another application instance is established then string like port:COMMAND_HELLO is sent.
     * If response received and it has the same format and parsed userID value is equal this application userID, than COMMAND_SHUTDOWN is send.
     * Another application instance will perform System.exit().     
     */    
    private static void discoverInstances() {
        int port = portDefault;
        for (int i = 0; i < portRange; i++) {
            Socket socket = null;
            try {
                socket = new Socket("127.0.0.1", port);
                socket.setSoTimeout(readTimeout);
                
                String request = String.valueOf(port) + ":" + COMMAND_HELLO;
                
                printLine(socket,request);
               
                String response = readLine(socket);                
                
                if (response != null) {
                    int index = response.indexOf(":");
                    if (index != -1) {
                        String uID = response.substring(index + 1);
                        if(thisApplicationUserID.equals(uID)){
                           close(socket);
                           socket = new Socket("127.0.0.1", port);                             
                           String command = String.valueOf(port) + ":" + COMMAND_SHUTDOWN;
                           printLine(socket,command);
                           System.out.println("ShutdownServer terminates instance on port:" + port); 
                        }                        
                    }
                }

            } catch (UnknownHostException ex) {
//                System.out.println("UnknownHostException:" + ex);                
            } catch(SocketTimeoutException ex){
//                System.out.println("SocketTimeoutException:" + ex);            
            } catch (IOException ex) {
//                System.out.println("IOException:" + ex);
            } finally {
               close(socket);
            }
            port++;
        }
                
    }
    
    public static void main(String[] a){  
        daemon = false;//when started from main
        start("TEST");
    }
}

PM MAIL   Вверх
koreyko
Дата 1.4.2013, 18:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 50
Регистрация: 20.4.2010

Репутация: нет
Всего: нет



COVD, спасибо. Вдумчиво изучил Ваш код, но так и не понял -- каким образом я все-таки могу получить из второй запущенной копии доступ к фрейму первой копии? Для того, чтобы развернуть свернутое в трей окно. 
PM MAIL   Вверх
batigoal
Дата 1.4.2013, 22:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 24
Всего: 151



koreyko, тебе не нужно получать доступ к чужому фрейму - это сам первый экземпляр программы слушает события на порту, и, получив сообщение от запущенного второго инстанса, разворачивает себя. Второй же экземпляр после получения сообщения тихо завершается.


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
koreyko
Дата 2.4.2013, 21:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 50
Регистрация: 20.4.2010

Репутация: нет
Всего: нет



batigoal, вы уверены? Потому что COVD писал, цитирую: "Когда вторая инстанс стартует, первая закрывается командой System.exit(0)"
PM MAIL   Вверх
batigoal
Дата 2.4.2013, 22:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 24
Всего: 151



koreyko, да, но выполняет-то этот System.exit сам инстанс, который будет выключен: 

Код

else if (command.equals(COMMAND_SHUTDOWN)) {//shutdown this application by command from another application    
                        System.out.println("app exits");
                        System.exit(0);
                    }


Программа получила сообщение и завершила себя.


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
COVD
Дата 3.4.2013, 00:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



koreyko
У меня действительно так сделано, что при запуске второго инстанса он шлет команду первому инстансу и первый сам себя закрывает по этой команде.  Я привел код, на основе которого вы можете реализовать свою логику, например, второй закрывается, а первый разворачивается. 
PM MAIL   Вверх
koreyko
Дата 3.4.2013, 11:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 50
Регистрация: 20.4.2010

Репутация: нет
Всего: нет



COVD,  еще раз спасибо. Разобрался, всё у меня получилось. Я раньше никогда не работал с сокетами и серверами, поэтому у меня осталась пара вопросов:

- что такое readTimeout, равный 2-м секундам и зачем он нужен? Насколько я понял, это диапазон, через который сервер слушает приходящие команды, или нет? Заметил такую ситуацию: если быстро запустить приложение 2 раза, то остаются запущенными две копии. Как с эти можно бороться?
- каким образом надо выбирать диапазон портов? Если все они оказались до этого заняты другими процессами, то данное решение не сработает? Или же это порты относятся только к запущенному серверу и они всегда свободны?
PM MAIL   Вверх
COVD
Дата 3.4.2013, 16:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Цитата

- что такое readTimeout, равный 2-м секундам и зачем он нужен?


Поток, читающий из сокета, блокируется, если нет данных (если сокет в блокирующем режиме). Таймаут на чтение определяет максимальное время ожидания данных. Если данных нет большее время, то выбрасывается исключение, и поток разблокируется. Это событие на принимающей стороне (на клиенте) означает, что коммуникация завершилась аварийно. Иначе поток может ожидать данных вечно.

2 сек - предполагается, что в локальной сети этого достаточно. Если обмен данных осуществляется через интернет, то обычно ставят секунд 15.

Цитата

если быстро запустить приложение 2 раза, то остаются запущенными две копии. Как с эти можно бороться?


Очевидно, что второе запущенное приложение начинает поиск, а первое приложение еще не успело запустить свой сервер, так как тоже ищет. Можно попробовать поменять местами операции - сначала стартовать сервер, а потом искать в сети другие инстансы.
И, наверное, надо передавать время старта в миллисек, чтобы инстансы могли понять, кто из них первый. 

Цитата

каким образом надо выбирать диапазон портов? Если все они оказались до этого заняты другими процессами, то данное решение не сработает?


Если все порты из диапазона заняты, то не сработает (сервер не сможет стартовать). Если расширить диапазон, то увеличится время поиска. Я думаю, 5 - 10 портов вполне достаточно для этих целей. Мир не рухнет, если данное решение вдруг не сработает. 
PM MAIL   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1391 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.