Android Framework 常见解决方案(20)UDP广播无效问题

news/2024/5/18 16:09:01 标签: android, udp, 网络协议

1 现象描述和原理解读

该问题同时存在于android App和Framework系统中。最终效果是在Android系统中直接使用UDP广播无效,有意思的是有的android系统可以,有的Android 系统不行。然而该部分代码自己在Linux上测试时是有效的,代码不变,只是简单的编译移植过来就变得莫名其妙的不行了,头还真是大的不行。

UDP广播接收端的关键实现程序如下所示:

#include <iostream>
#include <string>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

const int UDP_PORT = 19662;

int main() {
    int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (socket_fd == -1) {
        std::cerr << "Failed to create socket" << std::endl;
        return 1;
    }

    struct sockaddr_in local_address{};
    local_address.sin_family = AF_INET;
    local_address.sin_addr.s_addr = INADDR_ANY;
    local_address.sin_port = htons(UDP_PORT);

    if (bind(socket_fd, (struct sockaddr*)&local_address, sizeof(local_address)) == -1) {
        std::cerr << "Failed to bind socket" << std::endl;
        close(socket_fd);
        return 1;
    }

    std::cout << "Listening for UDP broadcast on port " << UDP_PORT << std::endl;

    char buffer[1024];
    struct sockaddr_in sender_address{};
    socklen_t sender_address_length = sizeof(sender_address);

    while (true) {
        ssize_t bytes_received = recvfrom(socket_fd, buffer, sizeof(buffer), 0,
                                          (struct sockaddr*)&sender_address, &sender_address_length);
        if (bytes_received == -1) {
            std::cerr << "Error receiving data" << std::endl;
            close(socket_fd);
            return 1;
        }

        std::string received_message(buffer, bytes_received);
        std::cout << "Received message from " << inet_ntoa(sender_address.sin_addr)
                  << ": " << received_message << std::endl;
    }

    close(socket_fd);
    return 0;
}

UDP广播发送端测试程序如下:

#include <iostream>
#include <string>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

const int UDP_PORT = 19662;
const std::string UDP_BROADCAST_ADDRESS = "192.168.1.255";

int main() {
    int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (socket_fd == -1) {
        std::cerr << "Failed to create socket" << std::endl;
        return 1;
    }

    int broadcast_enable = 1;
    if (setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, &broadcast_enable, sizeof(broadcast_enable)) == -1) {
        std::cerr << "Failed to enable broadcast" << std::endl;
        close(socket_fd);
        return 1;
    }

    struct sockaddr_in target_address{};
    target_address.sin_family = AF_INET;
    target_address.sin_port = htons(UDP_PORT);
    if (inet_pton(AF_INET, UDP_BROADCAST_ADDRESS.c_str(), &target_address.sin_addr) <= 0) {
        std::cerr << "Invalid address" << std::endl;
        close(socket_fd);
        return 1;
    }

    std::string message = "Hello UDP Broadcast!";
    ssize_t bytes_sent = sendto(socket_fd, message.c_str(), message.size(), 0,
                                (struct sockaddr*)&target_address, sizeof(target_address));
    if (bytes_sent == -1) {
        std::cerr << "Failed to send data" << std::endl;
        close(socket_fd);
        return 1;
    }

    std::cout << "Sent broadcast message: " << message << std::endl;

    close(socket_fd);
    return 0;
}

在移植到android的过程中实际上是使用android走JNI调用C++的方式来使用,这里就不详述了。

最后分析,发现,果然是android的问题。因为在 移动端 Android 系统中,使用 UDP 广播可能会引发一些耗电的问题,因为 UDP 广播需要 Wi-Fi 连接保持在活动状态,以便能够发送和接收数据包。为了避免在应用程序使用 UDP 广播时造成不必要的电池消耗,开发者可以考虑使用 Wi-Fi 锁来控制 Wi-Fi 连接的状态。

Wi-Fi 锁是 Android 提供的一种机制,允许应用程序在需要时保持 Wi-Fi 连接处于活动状态,而不会由于系统的网络管理策略而被关闭或断开连接。使用 Wi-Fi 锁,应用程序可以确保在需要进行网络通信时,Wi-Fi 连接一直保持活跃,从而避免了频繁的连接和断开过程,这有助于降低耗电量。

修改方案(Android All)

Wi-Fi锁的获取和释放源码如下所示:

import android.content.Context;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;

public class WifiLockManager {
    private WifiLock wifiLock;
    private WifiManager wifiManager;

    public WifiLockManager(Context context) {
        wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "MyWifiLock");
    }

    //获取锁
    public void acquireWifiLock() {
        wifiLock.acquire();
    }

    //释放锁
    public void releaseWifiLock() {
        if (wifiLock.isHeld()) {
            wifiLock.release();
        }
    }
}

这样在UDP广播时就不会出现连不上的情况了。实际上Wi-Fi 锁机制从 Android 1.0 版本就存在,但是随着不同版本的 Android 系统的发布和演变,该机制可能会有一些变化和改进。

具体的行为和影响因 Android 版本和设备厂商而异。在早期的 Android 版本中,Wi-Fi 锁主要用于控制 Wi-Fi 连接的休眠策略,以防止在连接处于活动状态时进入省电模式。然而,随着 Android 版本的更新,系统对网络管理策略进行了多次改进,旨在更好地平衡性能和电池寿命,因此 Wi-Fi 锁的影响和需求可能会因 Android 版本的变化而变化。

另外,不同的硬件厂商可能会在其定制的 Android 版本中对网络管理和电池优化策略进行调整。这意味着在某些设备上,Wi-Fi 锁的行为可能会受到硬件和厂商定制的影响,因此才会出现有的设备能直接广播而有的需要wifi锁这样的情况。


http://www.niftyadmin.cn/n/4952257.html

相关文章

回归预测 | MATLAB实现FA-SVM萤火虫算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现FA-SVM萤火虫算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现FA-SVM萤火虫算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本介绍…

Kubernetes(K8s)从入门到精通系列之十七:minikube启动K8s dashboard

Kubernetes K8s从入门到精通系列之十七:minikube启动K8s dashboard 一、安装minikube的详细步骤二、查看Pod三、启动dashboard四、创建代理访问dashboard五、远程访问dashboard一、安装minikube的详细步骤 Kubernetes(K8s)从入门到精通系列之十六:linux服务器安装minikube的详…

GAN生成对抗模型根据minist数据集生成手写数字图片

文章目录 1.项目介绍2相关网站3具体的代码及结果导入工具包设置超参数定义优化器&#xff0c;以及损失函数训练时的迭代过程训练结果的展示 1.项目介绍 通过用minist数据集进行训练&#xff0c;得到一个GAN模型&#xff0c;可以生成与minist数据集类似的图片。 GAN是一种生成模…

[oneAPI] 使用字符级 RNN 生成名称

[oneAPI] 使用字符级 RNN 生成名称 oneAPI特殊写法使用字符级 RNN 生成名称Intel Optimization for PyTorch数据下载加载数据并对数据进行处理创建网络训练过程准备训练训练网络 结果 参考资料 比赛&#xff1a;https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517…

logstash配置文件

input { kafka { topics > “xxxx” bootstrap_servers > “ip:port” auto_offset_reset > “xxxx” group_id > “xxxx” consumer_threads > 3 codec > “json” } } filter { grok { match > { “message” > ‘%{IP:client_ip} - - [%{HTTPDATE:…

使用自己的领域数据扩充baichuan模型词表(其他模型也一样)

文章目录 前言环境项目结构一、使用步骤二、训练词表三、合并词表四、效果前言 总的来说,扩充词表可以加快解码速度,对于对中文支持不太友好的模型(如llama),扩充词表还能提升模型在中文的表现。 环境 jsonlines==3.1.0 sentencepiece==0.1.99 transformers==4.28.1项目…

程序的DAC检查与LSM简介

程序的DAC检查 在Linux中&#xff0c;程序的DAC&#xff08;Discretionary Access Control&#xff0c;自主访问控制&#xff09;检查是指操作系统对程序执行期间对文件和资源的访问权限进行的检查。 Linux使用一种基于权限的访问控制模型&#xff0c;其中每个文件和资源都与…

OkHttp 源码浅析一

演进之路:原生Android框架不好用 ---- HttpUrlConnect 和 Apache HTTPClient 第一版 底层使用HTTPURLConnect 第二版 Square构建 从Android4.4开始 基本使用: val okhttp OkHttpClient()val request Request.Builder().url("http://www.baidu.com").buil…