@Dmtm
Android

Как правильно закрывать (переоткрывать) неблокирующий сокет из NIO?

переписываю древний проект, используется сокет из java.nio
в некоторый момент адрес сервера может измениться и надо пересоздать соединение, но channel.finishConnect() всегда false
для тестирования соединяюсь по тому же адресу, может быть в этом проблема? сервер считает старый сокет открытым?
есть корутина
fun createNioSocket(serverAddressString: String, serverPort: Int) {
        job?.cancel()
        job = scope.launch(Dispatchers.IO) {

            val serverIPAddress = InetAddress.getByName(serverAddressString)
            val serverAddress = InetSocketAddress(serverIPAddress, serverPort)

            var channel: SocketChannel? = null
            var selector: Selector? = null
            try {
                channel = SocketChannel.open()
                channel.configureBlocking(false)
                val channelConnectResult = channel.connect(serverAddress)
                Timber.d("channel.connect: $channelConnectResult")

                selector = Selector.open()
                val operations = SelectionKey.OP_CONNECT or SelectionKey.OP_READ or SelectionKey.OP_WRITE
                //selector.wakeup();
                val selectionKey = channel.register(selector, operations)

                var count = 0
                while (!channel.finishConnect() && count < 100) {
                    delay(50)
                    count++
                }
                if (channel.finishConnect()) {
                    Timber.d("channel.finishConnect() IS TRUE, count: $count")
                    _connectionState.emit(ConnectionState.Connected())
                } else {
                    Timber.e("channel.finishConnect() IS FALSE")   // <--------------при повторном запуске попадаем сюда всегда 
                    cancel()
                }

                while (isActive) {
                    selector.select(50)
                    val iterator: MutableIterator<SelectionKey> = selectionKey.selector().selectedKeys().iterator()
                    while (iterator.hasNext()) {
                        val key = iterator.next()
                        iterator.remove()

                        if (isActive && key.isReadable) {
                            //Timber.d("key.isReadable()")
                            try {
                                val data: ByteArray = processRead(key)
                                if (data.isNotEmpty()) {
                                    onIncomingData(data)
                                }
                            } catch (e: DisconnectException) {
                                Timber.e("DisconnectException while processRead")
                                cancel()
                            }
                        }
                        if (isActive && key.isWritable) {
                            //Timber.d("key.isWritable()");
                            sendMutex.withLock {
                                try {
                                    if (dataOut.isNotEmpty()) {
                                        processWrite(key, dataOut)
                                        dataOut = ByteArray(0)
                                    }
                                } catch (e: DisconnectException) {
                                    Timber.e("DisconnectException while processWrite")
                                    cancel()
                                }
                            }
                        }
                    }
                }
            } finally {
                Timber.d("job finally")

                val socket: Socket? = channel?.socket()

                try {
                    Timber.d("job finally, channel: $channel")
                    channel?.close()
                    Timber.d("1 job finally, selector: $selector, .isOpen: ${selector?.isOpen} ")  //true
                    Timber.d("1 job finally, socket: $socket, .isClosed ${socket?.isClosed}")   //true
                } catch (e: java.lang.Exception) {
                    e.printStackTrace()
                }
                try {
                    Timber.d("job finally, selector: $selector")
                    selector?.close()
                    Timber.d("2 job finally, selector: $selector, .isOpen: ${selector?.isOpen} ")   //false
                    Timber.d("2 job finally, socket: $socket, .isClosed ${socket?.isClosed}")   //true
                } catch (e: java.lang.Exception) {
                    e.printStackTrace()
                }
                try {
                    Timber.d("job finally, socket: $socket")
                    socket?.close()
                } catch (e: java.lang.Exception) {
                    e.printStackTrace()
                }
                dataOut = ByteArray(0)
                dataIn.setLength(0)

                _connectionState.emit(ConnectionState.Disconnected())
            }

        }

останавливается
fun disconnect() {
        Timber.d("disconnect() called")
        job?.cancel()
    }
  • Вопрос задан
  • 34 просмотра
Пригласить эксперта
Ответы на вопрос 1
@Dmtm Автор вопроса
Android
разобрался, в коде все правильно, просто сервер присылал новый адрес с ошибкой
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы