Исключение Android SocketException ‘Сокет закрыт’ закрывается даже после сокета.Используется функция isClosed()

#java #android #sockets #socketexception

#java #Android #сокеты #socketexception

Вопрос:

У меня есть приложение, в котором я использую сокет для прослушивания сообщений с сервера, в нем есть два действия, каждое из которых имеет свой собственный метод обработки сообщений.

Когда я запускаю второе из первого, я закрываю прослушиватель сокета для этого действия и запускаю новое во втором onCreate методе activities. Однако, когда я переключаю действия, я получаю java.net.SocketException: Socket is closed сообщение об ошибке.

 public synchronized void run(){
    //Check if the thread has been shut down
    while(!this.stopped){
        socket = null;
        try{
            //Socket
            socket = new DatagramSocket(port);
            //Packet
            byte[] data = new byte [1024];
            DatagramPacket packet = new DatagramPacket(data, data.length);
            if(!socket.isClosed()){
                //Store data from socket into packet
                socket.receive(packet);
                //Create a string from the data
                String received = new String(packet.getData(),packet.getOffset(),packet.getLength());

                //Log the string TODO remove this
                Log.i("RECEIVED", received);

                //Get a new message object from the handler
                Message msg = commandHandler.obtainMessage();
                //Store the string in the message
                msg.obj = received;
                //Send the message to the handler
                commandHandler.sendMessage(msg);
            }

        }catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(socket != null)
                socket.close();
        }
    }
}

/**
 * Close the listener
 */
public void shutDown(){
    this.stopped = true;
    if(socket != null){
        socket.close();
    }
}
 

Как вы можете видеть выше, я использую !socket.isClosed() , чтобы проверить, закрыт ли сокет перед получением сообщения

Трассировка ошибки:

 06-27 19:48:12.129: W/System.err(19460): java.net.SocketException: Socket closed
06-27 19:48:12.129: W/System.err(19460):    at libcore.io.Posix.recvfromBytes(Native Method)
06-27 19:48:12.129: W/System.err(19460):    at libcore.io.Posix.recvfrom(Posix.java:136)
06-27 19:48:12.129: W/System.err(19460):    at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:164)
06-27 19:48:12.129: W/System.err(19460):    at libcore.io.IoBridge.recvfrom(IoBridge.java:513)
06-27 19:48:12.129: W/System.err(19460):    at java.net.PlainDatagramSocketImpl.doRecv(PlainDatagramSocketImpl.java:161)
06-27 19:48:12.129: W/System.err(19460):    at java.net.PlainDatagramSocketImpl.receive(PlainDatagramSocketImpl.java:169)
06-27 19:48:12.129: W/System.err(19460):    at java.net.DatagramSocket.receive(DatagramSocket.java:253)
06-27 19:48:12.129: W/System.err(19460):    at com.android.homeservice.server.TabletListener.run(TabletListener.java:54)
 

Обновить

Итак, оказывается, что я дважды вызывал start() метод потока во втором действии, один раз onCreate и снова, в onStart котором он остался от предыдущей версии кода. В любом случае спасибо за все ваши ответы и извините, если я потратил ваше время впустую

Комментарии:

1. Сокет действительно может быть закрыт после проверки, закрыт ли он, например, во время ожидания получения данных. Когда и где вы вызываете socket.close()?

2. Я вызываю метод shutDown() перед тем, как создать намерение запустить новое действие, чтобы попытаться закрыть прослушиватель предыдущих

Ответ №1:

Я бы предложил перестроить архитектуру. Держите сокет, обрабатывающий все в потоке, и просто сообщите потоку, когда он должен завершиться. Когда поток выйдет, закройте гнездо.

 public synchronized void run(){
    //Check if the thread has been shut down
    Socket socket = new DatagramSocket(port);
    while(!this.stopped){
        socket = null;
        try{
            //Socket
            //Packet
            byte[] data = new byte [1024];
                //Store data from socket into packet
                socket.receive(packet);
                //Create a string from the data
                String received = new String(packet.getData(),packet.getOffset(),packet.getLength());

                //Log the string TODO remove this
                Log.i("RECEIVED", received);

                //Get a new message object from the handler
                Message msg = commandHandler.obtainMessage();
                //Store the string in the message
                msg.obj = received;
                //Send the message to the handler
                commandHandler.sendMessage(msg);
            }

        }catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(socket != null)
                socket.close();
        }
    }
    socket.close()
}

/**
 * Close the listener
 */
public void shutDown(){
    this.stopped = true;

}
 

Комментарии:

1. DatagramSocket.receive() блоки.

Ответ №2:

Очевидно, что кто-то другой закрыл его между тестом isClosed() и строкой, которая вызвала исключение.

Сделайте ‘socket’ локальной переменной, тогда никто другой не сможет ее закрыть.

Но создание сокета каждый раз вокруг цикла в первую очередь совершенно бессмысленно. Просто используйте одно и то же гнездо в течение всего срока службы нити. Если вы никогда не закроете его внутри цикла, он не сможет выдать это исключение, и вам никогда не нужно его проверять.