Spring’s Hot Swap features "Bindexception: Address already in use: Cannot bind"

Asked

Viewed 96 times

0

I’m working with a thread that keeps running Broadcasts to map network devices, but when I modify my code and Spring performs Hot Swap, I get Exception "Bindexception: Address already in use: Cannot bind".

Applying:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class BroadcastListeningThread {
    public static void startThreadToListenToBroadcasts() {
        new Thread() {
            @Override
            public void run() {
                try (DatagramSocket socket = new DatagramSocket(30333, InetAddress.getByName("0.0.0.0"))) {
                    socket.setBroadcast(true);
                    var responseBuffer = new byte[1024];
                    var responsePacket = new DatagramPacket(responseBuffer, responseBuffer.length);
                    String receivedResponse;

                    while (true) {
                        socket.receive(responsePacket);
                        receivedResponse = new String(responsePacket.getData(), 0, responsePacket.getLength());
                        System.out.println(receivedResponse);
                        DiscoveredWEXEquipments.addEquipment(receivedResponse);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

Error:

java.net.BindException: Address already in use: Cannot bind
    at java.base/java.net.DualStackPlainDatagramSocketImpl.socketBind(Native Method)
    at java.base/java.net.DualStackPlainDatagramSocketImpl.bind0(DualStackPlainDatagramSocketImpl.java:84)
    at java.base/java.net.AbstractPlainDatagramSocketImpl.bind(AbstractPlainDatagramSocketImpl.java:131)
    at java.base/java.net.DatagramSocket.bind(DatagramSocket.java:394)
    at java.base/java.net.DatagramSocket.<init>(DatagramSocket.java:244)
    at java.base/java.net.DatagramSocket.<init>(DatagramSocket.java:301)
    at br.com.manager.utils.CommunicationHelper.udpMessage(CommunicationHelper.java:16)
    at br.com.manager.equipmentdiscovery.DiscoverUsingBroadcastStrategy.lambda$0(DiscoverUsingBroadcastStrategy.java:18)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
    at br.com.manager.equipmentdiscovery.DiscoverUsingBroadcastStrategy.findAll(DiscoverUsingBroadcastStrategy.java:16)
    at br.com.manager.equipmentdiscovery.DiscoverNetworkEquipmentsInNetwork.run(DiscoverAllNetworkEquipmentsInNetwork.java:11)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:770)
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
    at br.com.manager.ManagerApplication.main(ManagerApplication.java:11)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

2 answers

1


I believe you’ve identified the problem. Looking at the code, I wondered what happened to the Thread you created when Spring tried to do Reload. Because it wasn’t meant to end (while (true) {), unless there is an exception or the application actually ends. So I implemented a solution similar to yours and added some logs to the code and verified that in the first interaction a Thread is created but when doing the Reload a new one is created using the same port which causes the Error. Where the application keeps repeatedly trying to start and open a new thread that results in failure...

The question now is how to finish Thread when doing Reload. Because using a system of available ports could generate multiple Threads doing the same process only in separate posts.

First interaction inserir a descrição da imagem aqui

When doing the Reload inserir a descrição da imagem aqui

Code for testing

package com.example.stackoverflow;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Set;

@SpringBootApplication
public class StackoverflowApplication {

public static void main(String[] args) {
    SpringApplication.run(StackoverflowApplication.class, args);
    startThreadToListenToWex350Broadcasts();
}

private static void startThreadToListenToWex350Broadcasts() {
    final String threadName = "THREAD_TESTE";
    final Thread thread = new Thread(getRunnable(), threadName);
    thread.start();

    Thread.getAllStackTraces().keySet().stream()
            .filter(t -> t.getName().equals(threadName))
            .forEach(t -> System.out.println(String.format(" id: %s - name: %s - state: %s", t.getId(), t.getName(), t.getState())));
}

private static Runnable getRunnable() {
    return () -> {
        try (DatagramSocket socket = new DatagramSocket(30333, InetAddress.getByName("0.0.0.0"))) {
            socket.setBroadcast(true);
            byte[] responseBuffer = new byte[1024];
            final DatagramPacket datagramPacket = new DatagramPacket(responseBuffer, responseBuffer.length);
            String receivedResponse;

            while (true) {
                socket.receive(datagramPacket);
                receivedResponse = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
                System.out.println(receivedResponse);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    };
}

}

0

For me, in an existing Springboot application using Intellij IDE v2019.1 the following project configuration and IDE was enough for Hot Swap to work.

1: Add the dependency below to pom.xml.

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>

2: Open the configuration menu Settings -> Build, Execution, Deployment -> Compiler and mark the option Build project Automatically.

3: Press Ctrl-Shift-A search for Registry and mark the option inside it Compiler.automake.allow.when.app.running.

4: Re-start the IDE.

Content above originated from the post Spring Boot Application Live Reload (Hot Swap) with Intellij IDEA

I hope I’ve helped.

  • Hot Swap is functioning normally. My problem is with the Datagramsocket port, which seems not to be being released during the Hot Swap, featuring the above exception.

  • I understand, sorry I didn’t mean your question. Dropping the application and restarting everything works normally?

  • Correct. Manually restarting the application works smoothly.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.