override fun onCreate() {
        debug("call onCreate >>>")
        val server = ServerKotlin()
        thread = Thread(server)
        thread.start()
    }

When creating the service, need to create a thread to run the server.

internal inner class ServerKotlin : Runnable {
        override fun run() {
            running = true

            debug("S: Connecting...")

            /* Create new UDP-Socket */
            socket = DatagramSocket(SERVERPORT) //50001 port로 UDP 서버를 실행 // , serverAddr
            socket!!.soTimeout = 1000
            socket!!.broadcast = true

						// 데이터 사이즈를 넉넉하게 세팅
            val buf = ByteArray(1500)

            while (running) { // client 요청을 기다려야해서 while문 사용
                /* Prepare a UDP-Packet that can
                * contain the data we want to receive */
                var packet = DatagramPacket(buf, buf.size)
                debug("S: Receiving...")

                /* Receive the UDP-Packet */
                try {
                    socket!!.receive(packet)
                } catch (e: java.lang.Exception) {
                    debug("UDP S: Error >>> $e")
                    continue
                }

                clientAddr = packet.address // client address
                clientPort = packet.port    // client port

                debug("clientAddr: $clientAddr")
                debug("clientPort: $clientPort")

                packet = DatagramPacket(buf, buf.size, clientAddr, clientPort)

								// 받은 패킷을 이용해서 데이터를 받는다
                val received = String(packet.data, 0, packet.length).trim { it <= ' ' }
                debug("UDP S: Received received >>>>>>>>>> $received")

                // thread pause, interrupt() to make terminate
                try {
                    Thread.sleep(1000)
                } catch (e: Exception) {}
            }
            // Log.d("UDP", "S: Socket Close.")
            debug("UDP clientAddr.toString() >>. ${clientAddr.toString()}")

        }
    }
override fun onDestroy() {
        debug("call onDestroy >>>")
        releaseUDPSocket() // 소켓 자원해제 함수

        if (!thread.isInterrupted)
						// 서비스가 종료되도 쓰레드가 계속 실행될 수 있으므로 쓰레드를 종료 시키게 한다.
            thread.interrupt() 

        super.onDestroy()
    }

Processing when the service is terminated.

		 /**
     * UDP socket resource release function
     */
    private fun releaseUDPSocket() {
        running = false
        socket?.broadcast = false
        socket?.close()
        try {
            socket?.soTimeout = 1;
        } catch (e: SocketException) {
        }
        socket?.disconnect()
        socket = null
    }

Example of Code

class UDPService : Service() {

    // udp server
    private var running = true
    private var socket: DatagramSocket? = null
    private var clientAddr: InetAddress? = null
    private var clientPort: Int = 0

    private var thread = Thread()

    override fun onCreate() {
        debug("call onCreate >>>")
        val server = ServerKotlin()
        thread = Thread(server)
        thread.start()

    }

    override fun onDestroy() {
        debug("call onDestroy >>>")

        releaseUDPSocket()
        val app = applicationContext as App
        app.isPingGood = false

        if (!thread.isInterrupted)
            thread.interrupt()

        super.onDestroy()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        debug("onStartCommand >>>>>>>>>>")
        return START_STICKY
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onUnbind(intent: Intent?): Boolean {
        debug("onUnbind >>>>>>>>>>")
        return true
    }

    /**
     * acheieved IP adress broadcast handling
     * @param ipStr IP adress
     */
    private fun sendMessage(ipStr: String) {
        val intent = Intent("message")
        intent.putExtra("url", ipStr)
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
    }

    internal inner class ServerKotlin : Runnable {
        override fun run() {
            running = true

            debug("S: Connecting...")

            /* Create new UDP-Socket */
            socket = DatagramSocket(SERVERPORT) //50001 port, UDP server execution , serverAddr
            socket!!.soTimeout = 1000
            socket!!.broadcast = true

            /* By magic we know, how much data will be waiting for us */
            val buf = ByteArray(1500)
            while (running) { // waiting client request
                /* Prepare a UDP-Packet that can
                * contain the data we want to receive */
                var packet = DatagramPacket(buf, buf.size)
                debug("S: Receiving...")

                /* Receive the UDP-Packet */
                try {
                    socket!!.receive(packet)
                } catch (e: java.lang.Exception) {
                    debug("UDP S: Error >>> $e")
                    continue
                }

                clientAddr = packet.address
                clientPort = packet.port

                debug("clientAddr: $clientAddr")
                debug("clientPort: $clientPort")

                packet = DatagramPacket(buf, buf.size, clientAddr, clientPort)

                val received = String(packet.data, 0, packet.length).trim { it <= ' ' }
                debug("UDP S: Received received >>>>>>>>>> $received")

                val app = (applicationContext as App)
                if (!app.isPingGood && received.isNotBlank()) {
                    // health check if device is not connected or not
                    val pingResult = pingFromUDP(received)
                    debug("UDP S: ping result >>>>>>>>>> $pingResult")
                    if (pingResult) {
                        app.setURL(received) // ip 셋팅
                    }
                }

                try {
                    Thread.sleep(1000)
                } catch (e: Exception) {}
            }
            // Log.d("UDP", "S: Socket Close.")
            debug("UDP clientAddr.toString() >>. ${clientAddr.toString()}")

        }
    }

    /**
     * UDP socket resource release function
     */
    private fun releaseUDPSocket() {
        running = false
        socket?.broadcast = false
        socket?.close()
        try {
            socket?.soTimeout = 1;
        } catch (e: SocketException) {
        }
        socket?.disconnect()
        socket = null
    }

    /**
     * dashcam connection check function
     * @param ipStr ip address
     * @return result
     */
    private fun pingFromUDP(ipStr: String): Boolean {
        val url = "<http://$ipStr:8888/action/>"
        return ClonAPIManager.instancePing(url).onErrorReturn { e ->
            val result = BaseResult()
            result.result = "failed"
            result.msg = e.message
            return@onErrorReturn BaseResult()
        }.blockingGet().isSuccess()
    }

    companion object {
        const val SERVERIP = "255.255.255.255" // 'Within' the emulator!
        const val SERVERPORT = 50001
    }
}