带插槽的Java单实例软件。 在Windows下关闭套接字的问题

我需要强制我的Java应用程序使用单个实例运行。 我在这个链接上找到了这段非常好的代码,它使用套接字而不是使用文件系统来解决问题。

在这里我调整:

package cern.ieplc.controller; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException;

import org.apache.log4j.Logger;

import java.io.BufferedReader; import 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认为不是那么容易。 一旦分配了资源,就永远不会释放。 如果我关闭软件,我将无法再次启动它,直到我关闭我的部分。

任何想法如何修复nicelly代码,使其在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(); } 

提前致谢

尝试

 ServerSocket socket = new ServerSocket(); socket.setReuseAddress(true); socket.bind(new InetSocketAddress(port)); 

http://download.oracle.com/javase/6/docs/api/java/net/ServerSocket.html#setReuseAddress%28boolean%29

当TCP连接关闭时,连接可能在连接关闭后的一段时间内保持超时状态(通常称为TIME_WAIT状态或2MSL等待状态)。 对于使用众所周知的套接字地址或端口的应用程序,如果在涉及套接字地址或端口的超时状态中存在连接,则可能无法将套接字绑定到所需的SocketAddress。

在使用bind(SocketAddress)绑定套接字之前启用SO_REUSEADDR允许套接字绑定,即使先前的连接处于超时状态。

不幸的是,Windows认为不是那么容易。 一旦分配了资源,就永远不会释放。 如果我关闭软件,我将无法再次启动它,直到我关闭我的部分。

这些陈述到底是什么意思? 如果进程终止,则在Novell Netware 3.x之外的任何操作系统上释放其所有资源。 您有什么证据表明侦听套接字未被关闭,以及当您尝试重新启动应用程序时会发生什么?