java.net.BindException:绑定失败:EADDRINUSE(地址已在使用)已在、绑定、地址、net

2023-09-07 16:14:58 作者:模仿不来的气质

我有一个服务,启动主题到插座上执行某些操作。在code如下:

I have a service, which starts Thread to perform some operations on socket. The code looks like:

 public class ServerRunnable implements Runnable {
    @Override
    public void run() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket();
            serverSocket.setReuseAddress(true);
            serverSocket.bind(new InetSocketAddress(ProtocolConstants.USB_SERVER_PORT));
        while (true) {
            Socket client = serverSocket.accept();
            // some code
        } catch (Exception e) {
            Log.e("Exception while listening on socket.", e);
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    Log.e(e);
                }
            }
        }

当我启动服务第一次,一切都很好,但我一直在使用 stopService 的方法来阻止它。当我开始这一次它返回以下异常:

When I start service first time, everything is ok, but then I have to stop it using stopService method. When I start it one more time it returns following exception:

java.net.BindException: bind failed: EADDRINUSE (Address already in use)

另外我补充的ServerSocket 结束在的onDestroy 服务的方法,但它并没有帮助。

In addition I added ServerSocket closing in onDestroy method of service but it did not help.

setReuseAddress 绑定执行,那么为什么它不工作?

The setReuseAddress is performed before bind, so why it is not working?

推荐答案

据我可以猜到它被卡在的ServerSocket.accept(),等待连接进来。因此,Runnable接口也从来没有关闭应用程序后结束。再次调用应用程序,让你这个错误(因为港口仍然被那是以前创建了Runnable阻止)。有处理这种多种方式:

As far as I can guess it gets stuck on serverSocket.accept(), waiting for a connection to come in. Hence the Runnable does never finish even after closing the app. Calling the app again gives you this error (because the port is still blocked by the Runnable that was created before that). There are multiple ways of handling this:

您可以拨打和停止的Runnable是这样的:

You can call and stop your Runnable like this:

ThreadPoolExecutor threadPoolExecutor = Executors.newSingleThreadExecutor();
Runnable longRunningTask = new Runnable();
Future longRunningTaskFuture = threadPoolExecutor.submit(longRunningTask);
longRunningTaskFuture.cancel(true); //this might not trigger right away

JProfiler 11 Java开发分析工具

您可以通过调用停止的ServerSocket.accept() serversocket.close()(其中将抛出一个需要处理到一个SocketException)

You can stop the serverSocket.accept() by calling serversocket.close() (which will throw a SocketException that needs to be handled)

我解决了这个(可能不是正确的操作方式)在发送数据(字符串)从的OnClose()方法,我的ServerSocket我的活动:

I solved this (might not be the correct way to handle this) by sending data (a string) to my serverSocket from the onClose() method in my Activity:

Socket socket = new Socket();
socket.setReuseAddress(true);
socket.connect((new InetSocketAddress(YOURSETTINGS, HERE);
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(new String("TIMEOUT"));
oos.close();
os.close();
socket.close();

您可以选择性地赶上这在你的服务器是这样的:

You can optionally catch this in your server like this:

ObjectInputStream objectInputStream = new objectInputStream(serverSocket.getInputStream());
Object object = objectInputStream.readObject();
if (object.getClass().equals(String.class) && ((String) object).equals("TIMEOUT"))
{
//Here you can do something with the Runnable before it is gone
}