数据报 (UDP) 接收器不工作 - 不接收广播数据包 [英] Datagram (UDP) receiver not working - not receiving broadcast packets

查看:25
本文介绍了数据报 (UDP) 接收器不工作 - 不接收广播数据包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了 UDP 数据报的问题,因为我无法从服务器接收 UDP 数据包,但我可以发送它们.我查看了许多示例,但无法弄清楚我的代码有什么问题.我终于从不同的网站找到了问题所在的提示.

I had a problem with UDP Datagrams in that I could not receive UDP packets from a server but I could send them. I looked through many examples but could not figure out what was wrong with my code. I finally found hints to what was going wrong from different sites.

因此,我在此处更新了问题,以防将来可能对某人有所帮助.下面的代码在 LG 手机上通过 WiFi 网络运行,并且基于 Android Studio 4.2 (29/4/2021);SDK平台30;Kotlin 1.5.0

I have thus updated the question here in case it might help someone in the future. The code below is working over a WiFi network on a LG phone and was built on Android Studio 4.2 (29/4/2021); SDK Platform 30; Kotlin 1.5.0

在下面代码部分的末尾,我写了一些关于是什么导致我的代码无法工作的注释.

At the end of the code section below I have written some comments as to what was causing my code not to work.

这是我的 MainActivity 代码

This is my MainActivity code

//Required includes
import android.os.Bundle
import android.os.StrictMode
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import java.io.IOException
import java.net.*


class MainActivity : AppCompatActivity() {

    //declared variables
    private var clientThread: ClientThread? = null
    private var thread: Thread? = null
    private var tv:TextView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_new)

        //Create a thread so that the received data does not run within the main user interface
        clientThread = ClientThread()
        thread = Thread(clientThread)
        thread!!.start()

        // create a value that is linked to a button called (id) MyButton in the layout
        val buttonPress = findViewById<Button>(R.id.MyButton)
        tv = findViewById(R.id.rcvdData)
        tv!!.text = "Data Captured"

        //Create a listener that will respond if MyButton is clicked
        buttonPress.setOnClickListener{
            //send a UDP package as a test
            sendUDP("Hello")
        }
    }



    //************************************ Some test code to send a UDP package
    fun sendUDP(messageStr: String) {
        // Hack Prevent crash (sending should be done using a separate thread)
        val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
        StrictMode.setThreadPolicy(policy)  //Just for testing relax the rules...
        try {
            //Open a port to send a UDP package
            val socket = DatagramSocket()
            socket.broadcast = true
            val sendData = messageStr.toByteArray()
            val sendPacket = DatagramPacket(sendData, sendData.size, InetAddress.getByName(SERVER_IP), SERVERPORT)
            socket.send(sendPacket)
            println("Packet Sent")
        } catch (e: IOException) {
            println(">>>>>>>>>>>>> IOException  "+e.message)
        }
    }

    //************************************* Some test code for receiving a UDP package
    internal inner class ClientThread : Runnable {
        private var socket: DatagramSocket? = null
        private val recvBuf = ByteArray(1500)
        private val packet = DatagramPacket(recvBuf, recvBuf.size)
        // **********************************************************************************************
        // * Open the network socket connection and start receiving a Byte Array                        *
        // **********************************************************************************************
        override fun run() {

            try {
                //Keep a socket open to listen to all the UDP trafic that is destined for this port
                socket = DatagramSocket(CLIENTPORT)
                while (true) {
                    //Receive a packet
                    socket!!.receive(packet)  

                    //Packet received
                    println("Packet received from: " + packet.address.hostAddress)
                    val data = String(packet.data).trim { it <= ' ' }
                    println("Packet received; data: $data")
                    //Change the text on the main activity view
                    runOnUiThread { tv?.text = data }
                }
            }
            catch (e1: IOException) {
                println(">>>>>>>>>>>>> IOException  "+e1.message)
                socket?.close()
            }
            catch (e2: UnknownHostException) {
                println(">>>>>>>>>>>>> UnknownHostException  "+e2.message)
                socket?.close()
            }
            finally{
                socket?.close()
            }
        }
    }

    companion object {
        val CLIENTPORT = 3000
        val SERVERPORT = 3000
        val SERVER_IP = "192.168.8.102"
    }
}

在我的清单文件中,我添加了这个权限

In my manifest file I added this permissions

<uses-permission android:name="android.permission.INTERNET"/>

activity_new.xml"仅包含一个 ID 为 MyButton 的按钮和一个 ID 为 rcvdData 的 TextView

The "activity_new.xml" only contains a button with id MyButton and a TextView with the id rcvdData

gradle.build(项目)

gradle.build (Project)

buildscript {
    ext.kotlin_version = "1.5.0"
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.2.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

gradle.build(模块)

gradle.build (Module)

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.udptry1"
        minSdkVersion 23
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

虽然我可以发送数据报 UDP 数据包,但我无法接收它们.在终于正确接收 UDP 数据包后,我只能接收 UNICAST 消息(仅针对我的 IP 的消息)而不是 BROADCAST 消息(针对多个设备的消息).

Although I could send datagram UDP packets I could not receive them. After finally getting it right to receive UDP packets, I could only receive UNICAST messages (messages only intended for my IP) and not BROADCAST messages (messages intended for multiple devices).

我无法接收消息的原因是我在 PC 上模拟接收器.Android 的模拟器会更改被模拟设备的 IP,并且不会将其绑定到 PC 的 IP 地址.这意味着虽然我的电脑会收到广播消息,但模拟的手机却没有.有关更多详细信息,请查看此链接(https://developer.android.com/studio/运行/模拟器网络)

The reason I could not receive messages was that I was emulating the receiver on my PC. Android's emulator changes the IP of the emulated device and does not bind it to the PC's IP address. This meant that although my PC would receive broadcasted messages, the emulated phone did not. For more details look at this link (https://developer.android.com/studio/run/emulator-networking)

我只能接收 UNCAST 而不能接收 BROADCAST 消息的原因是,一旦我的手机上的代码可以工作,我会在编码时离开手机.这意味着手机的屏幕将进入睡眠状态.显然有大量的手机会在手机进入睡眠状态时禁用收听广播消息以节省电力.一旦手机处于唤醒状态,它就会收听广播消息.

The reason I could only receive UNICAST and not BROADCAST messages was that once I got the code working on my cellphone, I would leave the phone while coding. This meant that the phone's screen would go to sleep. Apparently there is a large number of phones that DISABLE LISTENING to broadcast messages when the phone goes to sleep to conserve electricity. Once the phone is awake it would listen to broadcast messages.

获取多播锁定似乎不会影响我手机上的此功能(我尝试这样做只是为了广播,所以很遗憾,如果您实际上使用的是多播套接字而不是数据报套接字,我不知道它是否可以工作)

Getting a multicast lock did not seem to affect this functionality on my phone (I tried this only for broadcasting, so unfortunately I don't know if it might work if you were actually using a multicastsocket instead of a datagramsocket)

推荐答案

我找到了解决方案.代码实际上没有问题.我已经更新了原始问题,并对导致问题的原因进行了评论...请参阅上面的问题以获取完整说明.

I have found the solution. There was actually no issue with the code. I have updated the original question with comments on what caused the problem... Please see the question above for a full explanation.

简而言之,问题在于 Android 模拟器的 IP 与 PC IP 不同,其次手机进入睡眠状态后就停止收听广播消息.

In short the problem was with Android's emulator having a different IP to the PC IP and secondly the phone stopped listening to broadcasted messages once it goes to sleep.

这篇关于数据报 (UDP) 接收器不工作 - 不接收广播数据包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆