Android DatagramSocket error message: EADDRINUSE (

2020-02-26 04:30发布

问题:

I am trying to write a simple android chat app. I have created a service class which handles all the networking communication. The DatagramSocket binding is in a separate thread. Once in while I am getting this error and the app crashes:

java.net.BindException: bind failed: EADDRINUSE (Address already in use)
at libcore.io.IoBridge.bind(IoBridge.java:89)
at java.net.PlainDatagramSocketImpl.bind(PlainDatagramSocketImpl.java:68)
at java.net.DatagramSocket.createSocket(DatagramSocket.java:133)
at java.net.DatagramSocket.<init>(DatagramSocket.java:78)

and this is the code which prodruces it. The error occur on the line with new DatagramSocket How can I avoid this error? Thank you.

private class ComThread extends Thread {

        private static final int BCAST_PORT = 8779;
        DatagramSocket mSocket;
        InetAddress myBcastIP, myLocalIP;

        public ComThread() {

            try {
                myBcastIP = getBroadcastAddress();
                if (D)
                    Log.d(TAG, "my bcast ip : " + myBcastIP);

                myLocalIP = getLocalAddress();
                if (D)
                    Log.d(TAG, "my local ip : " + myLocalIP);

                if (mSocket == null) {
                    mSocket = new DatagramSocket(BCAST_PORT);
                    mSocket.setReuseAddress(true);
                    mSocket.setBroadcast(true);
                }           

            } catch (IOException e) {
                Log.e(TAG, "Could not make socket", e);
            }
        }

回答1:

You need to set SO_REUSEADDR before binding. Don't specify port in the constructor - create unbound socket instead with DatagramSocket(null), then set options, then bind() explicitly.



回答2:

Since Sean asked for the code, I have translated Nikola's answer to the following code, which is similar to what I am using in my app, in case it is useful:

if (mSocket == null) {
    mSocket = new DatagramSocket(null);
    mSocket.setReuseAddress(true);
    mSocket.setBroadcast(true);
    mSocket.bind(new InetSocketAddress(BCAST_PORT));
}


回答3:

Another reason that I faced,

In case you access a method that using your socket from an external thread, you have to make sure that the thread won't access the method more than once in the same time(or in another words won't create the socket more than one time), and despite the send and receive methods of the DatagramSocket are threadsafe, the construction of the DatagramSocket object is not, so you have to just synchronize the method that is capable of creating the DatagramSocket socket:

synchronized public void my_datagram_socket() throws Exception{

  // create the socket
  // operations through the socket
  // whatever you want

}