Kotlin Android 中可以实现 DatagramChannel 端口转发吗?

问题描述 投票:0回答:1

我目前正在尝试构建一个应用程序,该应用程序应该允许我转发 UDP 数据包。服务器将接收到的数据包寻址到目标服务器,并将从目标服务器接收到的数据包发送回客户端。其背后的目标是创建一个应用程序,使 Minecraft Bedrock 服务器可以通过 LAN 供控制台使用。我知道已经有这样的应用程序可用,但它们不必要地复杂,使用协议代理并且充满广告。这个应用程序应该很简单,因为它只转发数据,需要最少的更新,因此应该不需要太多努力即可工作。

我对

DatagramSocket
的尝试表明阻塞是有问题的,而可以禁用阻塞的
DatagramChannel
更适合。然而,我认为,这需要使用
DatagramChannel.register(Selector)
进行复杂的设置,作为 Kotlin 和 Android 应用程序开发的初学者,这可能会让人不知所措。

在某些时候,我尝试使用 ChatGPT 编写函数,虽然它生成了不错的模板,我可以稍后改进,但它似乎无法实现此代码,可能是由于网络上缺乏示例。我发现的示例会在客户端连接时导致崩溃。

到目前为止,我只成功地使用

DatagramSocket
建立了与世界数据的连接,但它阻塞太多,因此不适合。感觉就像是在攻击服务器。

因此,我的计划是使用

DatagramChannel
,但对我来说太复杂了。我的第一次尝试是没有
.register(Selector)
并且只有一个循环。虽然成功了,但随后我收到消息说消息太长,还不知道需要用
DatagramChannel.socket().setReceiveBufferSize(MAX_PACKET_SIZE)
来增加消息。 此外,我认为测试功能缺少检查是否已建立连接。

也许你们中一位经验丰富的开发人员可以在这里进一步帮助我,熟悉该主题的人可以告诉我使用 DatagramChannel 的方法是否正确,或者提供一个小例子。

https://github.com/JanisPlayer/Minecraft-Bedrock-Connect/blob/main/README.md CN:
数据包转发的基本思想可以在Android上用Userland进行测试:

screen -dmS socat socat UDP4-LISTEN:19132,fork,su=nobody UDP4:[164.68.125.80]:19132

Protocol:
wiki.vg/Raknet_Protocol
wiki.bedrock.dev/
Proxies:
github.com/Pugmatt/BedrockConnect/
github.com/CloudburstMC/Protocol
github.com/haveachin/infrared
github.com/cubeworx/cbwxproxy (Docker)
github.com/cubeworx/cbwxannounce/ (Source)
github.com/illiteratealliterator/manymine/ (clock jump)
developer.android.com/reference/java/net/DatagramSocket
developer.android.com/reference/java/nio/channels/DatagramChannel (Better solution than DatagramSocket)
Here is the DatagramChannel.configureBlocking(false),
DatagramChannel.socket().setReceiveBufferSize(MAX_PACKET_SIZE),
DatagramChannel.socket().setSoTimeout(100),
DatagramChannel.register(Selector) interesting.
github.com/elixsr/FwdPortForwardingApp/

MainActivity.kt 数据报套接字:

private fun startUDPServer() {
    try {
        val serverSocket = DatagramSocket(SOURCE_PORT, InetAddress.getByName("0.0.0.0"))
        val clientSocket  = DatagramSocket()

        var maxPacketSize = 65000
        var timeout = 100

        while (true) {
            try {
                serverSocket.setSoTimeout(timeout)
                serverSocket.setReceiveBufferSize(maxPacketSize)
                serverSocket.setSendBufferSize(maxPacketSize)
                clientSocket.setSoTimeout(timeout)
                clientSocket.setReceiveBufferSize(maxPacketSize)
                clientSocket.setSendBufferSize(maxPacketSize)

                val packet = DatagramPacket(ByteArray(maxPacketSize), maxPacketSize)
                serverSocket.receive(packet)

                Log.d(TAG, "Received UDP packet: ${packet.length}")

                val sendPacket = DatagramPacket(packet.data, packet.length, InetAddress.getByName(DESTINATION_IP), DESTINATION_PORT)
                clientSocket.send(sendPacket)

                val receivePacket = DatagramPacket(ByteArray(maxPacketSize), maxPacketSize, packet.address, packet.port)
                clientSocket.receive(receivePacket)

                receivePacket.address = packet.address
                receivePacket.port = packet.port

                serverSocket.send(receivePacket)
            } catch (e: Exception) {
                Log.d(TAG, "Error receiving UDP packet: ${e.message}")
            }
        }
    } catch (e: Exception) {
        Log.e(TAG, "Error starting UDP server: ${e.message}")
    }
}

我只能连接到世界数据,之后通常会失去连接。 如果没有超时,它就无法工作,因为它阻塞了太多。 这实际上应该被划分为线程,但所有这样做的尝试都以崩溃告终。此外,超时并不是数据未按发送和接收模式到达的问题的真正解决方案,因此只会使一切变慢并且不是为此目的。而且我还没有找到一种方法在DatagramSocket中创建一个线程只是为了接收,这样发送就不会被阻塞,整个程序也不会被阻塞。不过,这个功能在 DatagramChannel 中可用。

private fun startnewUDPServer() {
    try {
        // Create a DatagramChannel to receive UDP packets on the source port
        channel = DatagramChannel.open()
        channel.socket().bind(InetSocketAddress(SOURCE_PORT))
        channel.socket().setReceiveBufferSize(MAX_PACKET_SIZE)
        channel.socket().setSoTimeout(100)
        channel.configureBlocking(true)
        // Infinite loop to receive packets continuously
        val buffer = ByteBuffer.allocate(MAX_PACKET_SIZE)
        while (true) {
            buffer.clear()
            val senderAddress = channel.receive(buffer)
            // Forward the received packet to the destination if senderAddress is not null
            senderAddress?.let {
                Log.d(TAG, "Received data from $senderAddress.")
                buffer.flip()
                forwardPacket(buffer, it as InetSocketAddress, senderAddress) // senderAddress sent here twice because of an attempt.
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
        Log.d(TAG, "Error starting UDP server")
    }
}

private fun forwardPacket(buffer: ByteBuffer, senderAddress: InetSocketAddress, clientSenderAddress: SocketAddress) {
    try {
        // Create a new DatagramChannel for the forwarding process
        val forwardChannel = DatagramChannel.open()
        forwardChannel.socket().setReceiveBufferSize(MAX_PACKET_SIZE)
        forwardChannel.socket().setSoTimeout(1000)
        forwardChannel.configureBlocking(true)
        // Connect the forwarding channel to the destination address and port
        // Does it need to be checked to see if it is connected?
        forwardChannel.connect(InetSocketAddress(DESTINATION_IP, DESTINATION_PORT))
        // Send the package to the destination
        forwardChannel.write(buffer)
        val receiveBuffer = ByteBuffer.allocate(MAX_PACKET_SIZE)
        receiveBuffer.clear()
        val senderAddress = forwardChannel.receive(receiveBuffer)
        // Check if senderAddress is not null and then send the packet to the client
        if (senderAddress != null) {
            Log.d(TAG, "Received data from $senderAddress.")
            receiveBuffer.flip()
            //Send the data to the client
            channel.send(receiveBuffer, clientSenderAddress)
        }
        buffer.clear()
        // Need to close the channel after sending the packet?
        forwardChannel.close()
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

我尝试基于此项目使用ChatGPT复制UdpForwarder()函数。然后,我尝试纠正结果,但导致崩溃。 ChatGPT 提出的一些解决方案,比如

UdpForwarderTask()
,看起来有点荒谬,但我仍然尝试了它们,因为当时我自己的解决方案也好不了多少。 :D

android kotlin udp portforwarding datagram
1个回答
0
投票
private fun startNewUDPServer() {
    try {
        // Create a DatagramChannel to receive UDP packets on the source port
        val channel = DatagramChannel.open()
        channel.socket().bind(InetSocketAddress(SOURCE_PORT))
        channel.socket().setReceiveBufferSize(MAX_PACKET_SIZE)
        channel.socket().setSoTimeout(100)
        channel.configureBlocking(false)

        val forwardChannel = DatagramChannel.open()
        forwardChannel.socket().setReceiveBufferSize(MAX_PACKET_SIZE)
        forwardChannel.socket().setSoTimeout(1000)
        forwardChannel.configureBlocking(false)
        var clientSenderAddress: SocketAddress = InetSocketAddress(DESTINATION_IP, DESTINATION_PORT)
        var forwardSenderAddress: SocketAddress = InetSocketAddress(DESTINATION_IP, DESTINATION_PORT)

        // Infinite loop for continuous packet reception
        val buffer = ByteBuffer.allocate(MAX_PACKET_SIZE)
        while (true) {
            buffer.clear()
            val senderAddress = channel.receive(buffer)

            senderAddress?.let {
                Log.d(TAG, "Received data from $senderAddress: ${buffer}")
                buffer.flip()
                clientSenderAddress = senderAddress
                forwardChannel.send(buffer, forwardSenderAddress)
            }

            val receiveBuffer = ByteBuffer.allocate(MAX_PACKET_SIZE)
            receiveBuffer.clear()
            val forwardSenderAddress = forwardChannel.receive(receiveBuffer)

            forwardSenderAddress?.let {
                Log.d(TAG, "Received data from $forwardSenderAddress: ${receiveBuffer} $clientSenderAddress")
                receiveBuffer.flip()
                channel.send(receiveBuffer, clientSenderAddress)
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
        Log.d(TAG, "Error occurred")
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.