gpt4 book ai didi

带套接字的 Java 单实例软件。 windows下关闭socket的问题

转载 作者:行者123 更新时间:2023-12-02 09:43:49 26 4
gpt4 key购买 nike

我需要强制我的 Java 应用程序以单个实例运行。我发现this link这段非常好的代码使用套接字而不是使用文件系统解决了问题。

这是我调整后的:

包 cern.ieplc.controller;导入 java.net.InetAddress;导入 java.net.InetSocketAddress;导入 java.net.ServerSocket;导入java.net.Socket;导入 java.net.UnknownHostException;

导入org.apache.log4j.Logger;

导入java.io.BufferedReader;导入java.io.IOException;导入 java.io.InputStreamReader;导入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下想起来并不那么容易。资源一旦分配就永远不会释放。如果我关闭该软件,我将无法再次启动它,直到我关闭我的部分。

关于如何很好地修复代码以使其在 Windows 下运行的任何想法。我以为我可以使用关闭钩子(Hook)来捕获至少正常的关闭。不知道该怎么办,以防进程以意外方式终止。

这里我附上了通过 SW TCPView 完成的打印屏幕,该屏幕显示了 java 保持端口打开的方式: enter image description here

我尝试实现一个更简单的版本。还是同样的问题。 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);
}
}
}

有些想法没有正确关闭。如果我也将以下代码放入关闭钩子(Hook)中,它就不起作用:

//关闭服务器

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

When a TCP connection is closed the connection may remain in a timeout state for a period of time after the connection is closed (typically known as the TIME_WAIT state or 2MSL wait state). For applications using a well known socket address or port it may not be possible to bind a socket to the required SocketAddress if there is a connection in the timeout state involving the socket address or port.

Enabling SO_REUSEADDR prior to binding the socket using bind(SocketAddress) allows the socket to be bound even though a previous connection is in a timeout state.

关于带套接字的 Java 单实例软件。 windows下关闭socket的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7397769/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com