Мне нужно заставить мое приложение Java работать с одним экземпляром. Я нашел на эту ссылку этот очень хороший фрагмент кода, который решает проблему с помощью сокета вместо файловой системы.
здесь как я настроил:
пакет cern.ieplc.controller;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
импорт java.net.Socket;
import java.net.UnknownHostException;
import org.apache.log4j.Logger;
import java.io.BufferedReader;
импорт java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
public class ApplicationInstanceManager {
public interface ApplicationInstanceListener {
public void newInstanceCreated();
}
private static final Logger log = Logger.getLogger(CustomLock.class);
private static ApplicationInstanceListener subListener;
/** Randomly chosen, but static, high socket number */
public static final int SINGLE_INSTANCE_NETWORK_SOCKET = 44331;
/** Must end with newline */
public static final String SINGLE_INSTANCE_SHARED_KEY = "$$NewInstance$$\n";
private static ServerSocket socket;
/**
* Registers this instance of the application.
*
* @return true if first instance, false if not.
*/
public static boolean registerInstance() {
// returnValueOnError should be true if lenient (allows app to run on network error) or false if strict.
boolean returnValueOnError = true;
// try to open network socket
// if success, listen to socket for new instance message, return true
// if unable to open, connect to existing and send new instance message, return false
try {
socket = new ServerSocket(SINGLE_INSTANCE_NETWORK_SOCKET, 10, InetAddress.getByAddress(new byte[]{127,0,0,1}));
socket.setReuseAddress(true);//allows the socket to be bound even though a previous connection is in a timeout state.
socket.bind(new InetSocketAddress(SINGLE_INSTANCE_NETWORK_SOCKET));
log.debug("Listening for application instances on socket " + SINGLE_INSTANCE_NETWORK_SOCKET);
Thread instanceListenerThread = new Thread(new Runnable() {
public void run() {
boolean socketClosed = false;
while (!socketClosed) {
if (socket.isClosed()) {
socketClosed = true;
} else {
try {
Socket client = socket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String message = in.readLine();
if (SINGLE_INSTANCE_SHARED_KEY.trim().equals(message.trim())) {
log.debug("Shared key matched - new application instance found");
fireNewInstance();
}
in.close();
client.close();
} catch (IOException e) {
socketClosed = true;
}
}
}
}
});
instanceListenerThread.start();
// listen
} catch (UnknownHostException e) {
log.error(e.getMessage(), e);
return returnValueOnError;
} catch (IOException e) {
log.debug("Port is already taken. Notifying first instance.");
try {
Socket clientSocket = new Socket(InetAddress.getByAddress(new byte[]{127,0,0,1}), SINGLE_INSTANCE_NETWORK_SOCKET);
OutputStream out = clientSocket.getOutputStream();
out.write(SINGLE_INSTANCE_SHARED_KEY.getBytes());
out.close();
clientSocket.close();
log.debug("Successfully notified first instance.");
return false;
} catch (UnknownHostException e1) {
log.error(e.getMessage(), e);
return returnValueOnError;
} catch (IOException e1) {
log.error("Error connecting to local port for single instance notification");
log.error(e1.getMessage(), e1);
return returnValueOnError;
}
}
return true;
}
public static void setApplicationInstanceListener(ApplicationInstanceListener listener) {
subListener = listener;
}
private static void fireNewInstance() {
if (subListener != null) {
subListener.newInstanceCreated();
}
}
public static void closeInstance() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
log.error("Error while closing the socket");
}
}
}
}
Я попробовал код, и он отлично работает под Linux. если я закрою приложение (даже пытаясь убить его), сокет немедленно освобождается, и я могу запустить новое приложение!
К сожалению, под окнами думает, что это не так просто. если ресурс выделен, он никогда не освобождается. если я закрою программное обеспечение, я не смогу запустить его снова, пока не закрою свой раздел.
Любая идея о том, как исправить код, чтобы он работал под Windows.
Я думал, что смогу использовать отключающий крюк, чтобы поймать хотя бы нормальное отключение.
На самом деле не знаю, что делать, если он неожиданно завершит процесс.
Здесь я прилагаю экран печати, выполненный поверх SW TCPView, который показывает, как порт остается открытым с помощью Java:
Я попытался реализовать гораздо более простую версию. все та же проблема. под windows ресурсы не освобождаются.
Вот второй код:
import java.net.ServerSocket;
import javax.swing.JOptionPane;
import javax.swing.JFrame;
import java.io.IOException;
import java.net.BindException;
class MyApplication{
public static ServerSocket serverSocket;
public static void main(String as[])
{
try
{
//creating object of server socket and bind to some port number
serverSocket = new ServerSocket(15486);
////do not put common port number like 80 etc.
////Because they are already used by system
JFrame jf = new JFrame();
jf.setVisible(true);
jf.setSize(200, 200);
}
catch (BindException exc)
{
JOptionPane.showMessageDialog(null, "Another instance of this application is already running.", "Error", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
catch (IOException exc)
{
JOptionPane.showMessageDialog(null, "Another instance of this application is already running.", "Error", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
}
}
Есть что-то, что не подходит правильно.
Это не работает, если я вставлю в ловушку отключения следующий код:
// выключить сервер
try{
serverSocket.close();
}catch (IOException e) {
e.printStackTrace();
}
Заранее спасибо