JavaOSC协议使用教程-以及遇到的坑(UTF-16BE中文乱码)

一、导入Jar包

百度搜索maven仓库,进入搜索JavaOSC,有个javaosc core就是我们要下载的包了,提供了各种构建工具的导入方式。

gradle导入

dependencies {
        compile("com.illposed.osc:javaosc-core:0.4")
}

maven导入

<!-- https://mvnrepository.com/artifact/com.illposed.osc/javaosc-core -->
<dependency>
    <groupId>com.illposed.osc</groupId>
    <artifactId>javaosc-core</artifactId>
    <version>0.4</version>
</dependency>

二、什么是JavaOSC协议

1. 简介

osc协议是基于udp的,所以原理和udp差不多,都是服务端将信息推送(广播)到前端或者另外一个数据接收系统,只不过对传输格式做了进一步的封装。就像电视台广播一样,如果你的电视接收端没有打开,那么这一段时间的数据将会丢失,不可复现。

javaosc是对osc协议的具体实现。对一些api做简单的介绍:

发送api
OSCPortOut//发送对象,需要设置要发送到的目标主机的地址(InetAddress)和端口(port),调用send方法,即可发送信息。
OSCMessage//要发送的具体信息,要设置一个标识位地址(address),和具体要发送的内容。发送的内容是一个集合,多次调用addArgument()方法添加参数,内部会将这些参数放入一个有序集合,接收方接收到信息时,也是按照这个顺序来取相应的信息的。这一个不理解的话,看demo就能理解了。
OSCBundle//调用addPacket(OSCMessage message)方法将上面的发送信息封装进来,这一步主要是给内容体加上OSC协议的统一格式。
接收api
OSCPortIn//接收对象,需要设置监听的端口(port),也就是发送方发送的端口。addListener(String address, OSCListener listener);方法是添加一个监听标识位地址(address)的监听器,就是监听发送方发送的标识位地址。startListening()就是启动监听,就好像线程的start方法一样,调用之后才开始执行。

OSCListener//监听到某个地址的处理行为,这是一个接口,需要自己实现方法,下文的demo将会用java8的lambda表达式进行实现。

三、简单示例

先启动接收方(等待接收),之后再启动发送方,在控制台就可以看到打印信息了,可以自己打断点debug观察下运行流程。

import com.illposed.osc.*;
import org.junit.Test;

import java.net.InetAddress;
import java.net.SocketException;

/**
 * @Author kingboy
 * @Date 2017/6/9 15:36
 * @Description JavaOSCDemoTest is used to
 */
public class JavaOSCDemoTest {
    //发送方
    @Test
    public void send() throws Exception {
        /*------------------------------设置要发送的目标主机的IP地址------------------------------------*/
        InetAddress ipAddr = InetAddress.getByName("127.0.0.1");
        /*------------------------------设置要发送的目标主机的端口------------------------------------*/
        Integer port = 7000;
        /*------------------------------准备个快递员------------------------------------*/
        OSCPortOut out = new OSCPortOut(ipAddr, port);
        /*------------------------------准备要送的物件------------------------------------*/
        //来个箱子,准备装东西
        OSCMessage message = new OSCMessage();
        //给箱子上贴个快递单,告诉快递员要送到业主家的哪个位置
        message.setAddress("/test");
        //给箱子里装东西,先放十块钱进去,再放一个蛋糕进去
        message.addArgument(10);
        message.addArgument("蛋糕");
        //给箱子套上一个保护袋
        OSCBundle pack = new OSCBundle();
        pack.addPacket(message);
        /*--------------------------------快递员送件----------------------------------*/
        //把打包好的东西送走
        out.send(pack);
    }
    //接收方
    @Test
    public void receive() throws Exception {
        /*------------------------------准备个业主------------------------------------*/
        OSCPortIn in = new OSCPortIn(7000);
        /*------------------------------定义业主拿到快递的行为------------------------------------*/
        //挨个拿出来看看啥东西
        OSCListener listener = (data, message) -> {
            System.out.println("时间:" + data.toString());
            System.out.println("拿到快递了----");
            message.getArguments().forEach(mess -> System.out.println("东西是:" + mess.toString()));
        };
        /*------------------------------让业主到/test位置去等待快递------------------------------------*/
        in.addListener("/test", listener);
        in.startListening();
        /*------------------------------其它操作------------------------------------*/
        Thread.sleep(100000);
    }

}

四、遇到的坑

因为是和前台的ventuz软件进行对接,而ventuz的osc协议只接收UTF-16BE的编码(不明白的找度娘)。这时候找了api发现可以设置编码,但是ventuz接收到之后直接乱码,瞬间蒙蔽,招你惹你了。查了相关资料,发现UTF-16BE需要特殊的字节码处理,也就是说要在每个message的字节码需要加入特定的字节数组表示这是一个UTF-16BE编码的字节信息。这样ventuz接收到消息后就能正确解析了。

不说多了,直接上代码:(自己封装的工具类,只适合我自己的业务场景,如有需要,自行修改,我的业务是只发送一条个消息,这个消息是json字符串,交给ventuz自己来解析了,当然也可以逐条发送,但是太麻烦了,就偷了个懒)

注意其中的getByteFromString()方法就是对字节码进行了修改

package com.kingboy.springboot.common.utils;

import com.illposed.osc.OSCBundle;
import com.illposed.osc.OSCMessage;
import com.illposed.osc.OSCPortOut;

import java.io.UnsupportedEncodingException;
import java.net.InetAddress;

/**
 * @Author kingboy
 * @Date 2017/5/11 11:34
 * @Description OSCUtils is used to
 */
public class OSCUtils {

    /**
     *正式环境使用
     * @param path 传入的接口名称
     * @param msg   传入的内容
     */
    public static void sendMessage(String path, String msg) {
        try {

            //定义地址、端口、接收路径
            InetAddress address = InetAddress.getByName("127.0.0.1");
            Integer port = 7000;
            //定义发送
            OSCPortOut out = new OSCPortOut(address, port);
            //发送的内容
            OSCMessage message = new OSCMessage();
            //使用bundle包装message将会使其更完善
            OSCBundle bundle = new OSCBundle();
            //设置接口名称
            message.setAddress(path);
            //将字符串转为utf-16BE格式
            byte[] msgByte = OSCUtils.getByteFromString(msg);
            //增加内容
            message.addArgument(msgByte);
            //使用bundle包裹message
            bundle.addPacket(message);
            //发送
            out.send(bundle);
        } catch (Exception e) {
            System.err.println("osc信息推送失败!请检查网络连接!");
        }


    }

    /**
     * @param str 推送的信息
     * @return 转码后的信息
     * @throws UnsupportedEncodingException
     */
    public static byte[] getByteFromString(String str) throws UnsupportedEncodingException {
        //将传入的字符串转为utf-16BE格式的字节
        byte[] bytes = str.getBytes("UTF-16BE");
        //要在字节头部添加规定内容,设置好字节总长度
        int i = bytes.length + 4;
        //创建容器
        byte[] allBytes = new byte[i];
        //添加指定内容
        allBytes[0] = 0x42;
        allBytes[1] = 0x45;
        allBytes[2] = 0x55;
        allBytes[3] = 0x43;
        //将传入的字符串字节进行追加
        for (int j = 0; j < bytes.length; j++) {
            allBytes[j + 4] = bytes[j];
        }
        //将全新的内容返回
        return allBytes;
    }
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值