Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Android UDP协议,实现Yodar遥控器

Android UDP协议,实现Yodar遥控器

作者头像
饮水思源为名
发布于 2019-06-15 06:23:53
发布于 2019-06-15 06:23:53
68300
代码可运行
举报
文章被收录于专栏:Android小菜鸡Android小菜鸡
运行总次数:0
代码可运行

近期做了一个Yodar的音乐播放器,其实就是在Android上做了一个Yodar的遥控器,用了播放器的样式与Yodar的设备屏幕同步。而比较麻烦得是Yodar的协议是UDP的。并且涉及到发json数据,不能有丝毫错误,必须按规则来,否则不会返回任何信息。接下来,笔者就简单描述下制作过程中碰到的一些问题。还有,音乐播放器的源码属于公司产品项目,所以笔者上传的源码是测试写的API源码,当然与实际项目比较,也就差了一个界面和交互而已,核心的都在。

UDP的发送和接收

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class UDPUtil {
    private static UDPUtil udpUtil;
    DatagramSocket ds;
    private final int SENDPORT=10061;
    private final int REVCIVEPORT=10062;
    private final int SOCKETTIMEOUT=1000;
    private final String IP="255.255.255.255";
    private OnResolveDataListener onResolveDataListener;
    private UDPUtil() throws IOException {
        init();
        startUDPService();
    }
    private void init() throws IOException {
        ds= new DatagramSocket(REVCIVEPORT);
        ds.setBroadcast(true);
//        ds.setSoTimeout(SOCKETTIMEOUT);//设置超时时间
    }
    public synchronized static UDPUtil  getInstance() throws IOException {
        if (udpUtil==null) udpUtil=new UDPUtil();
        return udpUtil;
    }
    public void sendUDP(final byte[] sendBuf){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    DatagramPacket sendDp = new DatagramPacket(sendBuf, sendBuf.length, InetAddress.getByName(IP), SENDPORT);
                    ds.send(sendDp);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    public void startUDPService(){
        if(ds==null)return;
        Log.i("wsy","UDP Service star");
        new Thread(new Runnable() {
            @Override
            public void run() {
                byte[] receiveBuf = new byte[1024];
                DatagramPacket receiveDp = new DatagramPacket(receiveBuf, receiveBuf.length);
                while (true){
                    try {
                        ds.receive(receiveDp); // 该方法为阻塞式的方法
                        String ip = receiveDp.getAddress().getHostAddress();
                        int port = receiveDp.getPort();
                        byte[] text = receiveDp.getData();
//                        for (int i=0;i<receiveDp.getLength();i++) {
//                            Log.d("wsy","接收到第"+i+"byte的值="+ text[i]);
//                        }
                        Log.d("wsy", ip + ":" + port + ":" + byteToString(text, 0, receiveDp.getLength()));
                        if(onResolveDataListener!=null) onResolveDataListener.resolveData(text,receiveDp.getLength());
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.e("wsy","UDP Service error end");
                    }
                }
            }
        }).start();

    }
    /**
     * 将Byte转为String(按照ASCLL码表将10进制的byte值转成字符)
     * @param b
     * @param start
     * @param len
     * @return
     */
    public String byteToString(byte[] b,int start,int len){
        try {
            byte[] bytes=new byte[len];
            for (int i=start;i<start+len;i++){
                bytes[(i-start)]=b[i];
            }
            return new String(bytes,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "转化出错";
    }
    public interface OnResolveDataListener{
        void resolveData(byte[] bytes,int len);
    }

    public void setOnResolveDataListener(OnResolveDataListener onResolveDataListener) {
        this.onResolveDataListener = onResolveDataListener;
    }
}

这方面知识点文章很多,直接上代码,笔者做了一个单例类来管理这个UDPUtil,实现了UDP的发送和接收,以及byte和String的转化方法。默认广播IP“255.255.255.255”,发送端口10061(YodarUDP协议监听的这个端口),接收端口10062(不是10061就好,否则会接收到自己发的UDP包)

编写API,发送与接收

首先做这一步,得阅读Yodar的协议文档。发送则按照要求构建btye[]数据。下面是获取主机信息的例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 public void getHostInfo() {
        byte[] sendBuf = new byte[3];
        sendBuf[0] = (byte) 0xce;
        sendBuf[1] = 0x00;
        sendBuf[2] = (byte) (0xce ^ 0x00);
        udpUtil.sendUDP(sendBuf);
    }

接收的话,笔者通过协议的信息对不同的数据做了判断,截取获取到的JSON数据,构建对应的Bean类,然后通过广播发送给监听了对应Action的使用者。 这么做的目的是,UDP获取数据的时间不是我们控制的,也不是一定是发一条就接收一条,并且在Yodar切换歌曲等的时候,发主动发送UDP包给我们,我们需要一直去接收,自己判断属于什么数据,然后分发。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public void resolveData(byte[] bytes,int len) {
        Map<String, Object> maps=new HashMap<>();
        Intent intent=new Intent();
        intent.setAction(BROADCASTMESSAGE);
        switch (bytes[0]){
            case (byte) 0xef://主机信息返回
                maps.put("Command",bytes[0]);
                maps.put("Address",bytes[5]);
                maps.put("Model",bytes[4]);//通道数
                maps.put("iphoneId",bytes[5]);//编号
                maps.put("NameId",bytes[6]);
                maps.put("Name",udpUtil.byteToString(bytes,8,bytes[7]));
                hostInfo=maps;
                intent.putExtra("bean",gson.fromJson(gson.toJson(maps), HostInfoBean.class));
                break;
            case (byte)0x0f:
                String josnStr=udpUtil.byteToString(bytes,4,len-5);
                JSONObject jsonObject=null;
                String ack="";
                String notify="";
                JSONObject arg=null;
                try {
                    jsonObject=new JSONObject(josnStr);
                    try{
                        ack=jsonObject.getString("ack");
                    }catch (JSONException e){ }
                    try{
                        notify=jsonObject.getString("notify");
                    }catch (JSONException e){ }
                    try{
                        arg=jsonObject.getJSONObject("arg");
                    }catch (JSONException e){ }
                    if(!ack.equals("")){
                        switch (ack){
                            case "player.info"://歌曲信息---请求的
                                processMusicInfo(arg.toString(),intent);
                                break;
                            case "list.dirNodeList":
                                TableBean tableBean=new Gson().fromJson(josnStr, TableBean.class);
                                intent.putExtra("bean",tableBean);
                                break;
                        }
                    }
                    if(!notify.equals("")){
                        switch (notify){
                            case "player.info"://歌曲信息---通知的
                                processMusicInfo(arg.toString(),intent);
                                break;
                            case "player.time":
                                TimeNotifyBean timeNotifyBean=new Gson().fromJson(arg.toString(), TimeNotifyBean.class);
                                intent.putExtra("bean",timeNotifyBean);
                                break;
                            case "player.state":
                                StateNotifyBean stateNotifyBean=new Gson().fromJson(arg.toString(), StateNotifyBean.class);
                                intent.putExtra("bean",stateNotifyBean);
                                break;
                            case "player.mode":
                                ModeNotifyBean modeNotifyBean=new Gson().fromJson(arg.toString(), ModeNotifyBean.class);
                                intent.putExtra("bean",modeNotifyBean);
                                break;
                            case "player.volume":
                                VolumeNotifyBean volumeNotifyBean=new Gson().fromJson(arg.toString(), VolumeNotifyBean.class);
                                intent.putExtra("bean",volumeNotifyBean);
                                break;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
                break;
        }
        mC.sendBroadcast(intent);
    }

几分钟不操作之后,发送的非主机获取UDP包,Yodar不再响应问题

笔者做Android版本的Yodar遥控器时碰到了这个问题,据IOS说没有这个问题。笔者只好20S间隔一次,去给Yodar发送一个获取主机信息的UDP包,就不会出现Yodar不响应的问题。感觉就像发心跳包,需要一直保持联系。笔者也没搞明白为什么,这UDP协议按道理是不需要这样的牵手的。

源码

Yodar遥控器测试项目源码 YodarUDP协议在源码根目录中!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019.06.11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
实验三 音乐播放器
1、掌握服务的基本概念,能编写服务过程并进行调用; 2、掌握广播的基本概念,能实现广播通信。 3、需实现的具体功能为: 短信到来时自动产生的系统广播→激活音乐播放服务程序→活动组件程序使得停止按钮可用。 实现思路 • MainActivity启动服务,将播放、暂停、停止、切换信号发送广播给Service • MusicService 调用函数Prepareandplay()播放音乐,发送广播给MainActivity返回歌曲id • PrepareAndPlay() 定向操作 打开并播放音乐文件 注意的点 • 记得在配置文件中注册服务 • 注意findViewById在Fragment的使用方法 • 在Fragment中给ImageButton绑定事件监听器要重写onActivityCreated方法
twelvecoder
2021/12/24
1.5K0
实验三 音乐播放器
自定义Androidk全量更新组件
  自动更新功能对于一个APP来说是必备的功能,特别是对于未投放市场下载的APP,每次都让用户删掉原来的,再下载新的版本,肯定是不合适的。
饮水思源为名
2018/09/06
1.2K0
Android裁剪头像上传到远程服务器
 android从图库选择图片或者拍照后对图片进行裁剪,裁剪后上传到腾讯云服务器。
黄林晴
2019/01/10
1.6K0
【原创】com.baidu.ocr.sdk.exception.SDKError[283604]
异常com.baidu.ocr.sdk.exception.SDKError[283604]App identifier unmatch.错误的packname或bundleId.logId::30309247
趣学程序-shaofeer
2020/06/12
1.3K0
UDP协议发送/接收数据实现
UDP 是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接,简单来说,当客户端向接收端发送数据时,客户端不会确认接收端是否存在,就会发出数据。同样接收端在接收数据时,也不会向发送端反馈是否收到数据 由于使用 UDP 协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据传输 例如:视频会议通常采用 UDP 协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用 UDP 协议传送数据时,由于 UDP 的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用 UDP 协议
ITer.996
2022/11/22
2.5K0
UDP协议发送/接收数据实现
Android应用界面开发——BroadcastReceiver(实现基于Service的音乐播放器)
BroadcastReceiver用于接收程序(开发者开发的程序和系统程序)发出的Broadcast Intent,程序启动BroadcastReceiver需要两步:
trampcr
2018/09/28
1.6K0
Android应用界面开发——BroadcastReceiver(实现基于Service的音乐播放器)
大数据必学Java基础(八十二):基于UDP的网络编程
服务器端: ServerSocket --> Socket 程序感受到的使用流 :输入流
Lansonli
2022/11/10
3570
大数据必学Java基础(八十二):基于UDP的网络编程
Java简单实现UDP和TCP
该文章介绍了如何使用Java编写一个简单的TCP服务端和客户端,以及使用UDP实现简单的服务器和客户端。同时,还介绍了一种使用多线程来提高服务器接受客户端数据的能力的方法。
李家酒馆酒保
2017/12/28
1.1K0
Java简单实现UDP和TCP
Java---网络编程(2)-UDP
☆ UDP 将数据及源和目的封装成数据包中,不需要建立连接 每个数据报的大小在限制在64k内 因无连接,是不可靠协议 不需要建立连接,速度快
谙忆
2021/01/21
3560
【愚公系列】2022年01月 Java教学课程 66-网络编程-UDP通信
UDP协议是一种不可靠的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接收数据的对象,因此对于基于UDP协议的通信双方而言,没有所谓的客户端和服务器的概念
愚公搬代码
2022/01/15
3190
【愚公系列】2022年01月 Java教学课程 66-网络编程-UDP通信
基于UDP的网络数据传输测试(Java+Android)
零、前言 1.本文不是大讲特讲UDP和TCP的区别,或者其流程,只是基于此作些小测试 2.完成两个计算机、手机、计算机与手机之间的信息数据传输 3.把控制台输出及GUI操作 以及Android展
张风捷特烈
2018/10/08
1.6K0
基于UDP的网络数据传输测试(Java+Android)
Android:CoolWeather天气查看器
但是由于网络地址的问题一直加载不出来,所以也没法通过安装查看。不过从这个软件还是可以学到很多东西。
提莫队长
2019/03/01
1.1K0
Android popupMenu
popupMenu = new PopupMenu(ActivityHousesNumList.this, imageViewhousesnum1); popupMenu.getMenuInflater().inflate(R.menu.menu_device_config, popupMenu.getMenu()); popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListe
杨奉武
2018/12/21
6010
Android原生下载(下篇)多文件下载+多线程下载
零、前言 1.上篇实现了单线程的单文件下载,本篇将讲述多文件的多线程下载,在此之前希望你先弄懂上篇 2.本篇将用到上篇之外的技术: 多线程、线程池(简)、RecyclerView、数据库多线程访
张风捷特烈
2018/12/12
15.5K1
在Java中实现UDP协议编程(DatagramSocket/DatagramPacket)「建议收藏」
大家好,又见面了,我是你们的朋友全栈君。1.什么是UDP协议? UDP( User Datagram Protocol )协议是用户数据报,在网络中它与TCP协议一样用于处理数据包。在OSI模型中,在第四层——传输层,处于IP协议的上一层。 UDP是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。 2.为什么要使用UDP?
全栈程序员站长
2022/09/06
1.5K1
网络通信学习笔记(四)---UDP通信
这里我们首先需要明白一点,UDP本身就是一种不需要连的协议,所以是不存在客户端与服务端的.
萌萌哒的瓤瓤
2021/01/13
6450
网络通信学习笔记(四)---UDP通信
编程怎么入门_损失函数的基本概念和原理
本篇文章完全是一个铺垫,是为了后面文章提供理论基础,没有这些基础,谈论Socket编程和后续的具体功能实现,都是纸上谈兵,所以还请很少接触Socket编程的看官耐心看完这篇文章,相信对各位有好处。
全栈程序员站长
2022/11/02
2120
相关推荐
实验三 音乐播放器
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验