鸿蒙开源组件——bizsocket

jacksky
发布于 2021-10-18 18:16
浏览
0收藏

bizsocket

项目介绍

  • 项目名称:bizsocket
  • 所属系列:OpenHarmony的第三方组件适配移植
  • 功能:断线重连、一对一请求、通知、粘性通知、串行请求合并、包分片处理(AbstractFragmentRequestQueue)、缓存、拦截器、支持rxjava,提供类似于retrofit的支持、提供rxjava和rxjava2两种使用方式
  • 项目移植状态:主功能已完成
  • 调用差异:无
  • 开发版本:sdk6,DevEco Studio2.2 Beta1
  • 基线版本:Release v2.0.0

安装教程

1、在项目根目录下的build.gradle文件中

allprojects {
    repositories {
        maven {
            url 'https://s01.oss.sonatype.org/content/repositories/releases/'
        }
    }
}

2.在entry模块的build.gradle文件中

--RxJava2

dependencies {
       implementation('com.gitee.chinasoft_ohos:bizsocket_rx1:1.0.0')
       implementation('com.gitee.chinasoft_ohos:bizsocket_logger:1.0.0')
       implementation('com.gitee.chinasoft_ohos:bizsocket_tcp:1.0.0')
       implementation('com.gitee.chinasoft_ohos:bizsocket_core:1.0.0')
   ......  
}

-RxJava

dependencies {
   implementation('com.gitee.chinasoft_ohos:bizsocket_rx2:1.0.0')
   implementation('com.gitee.chinasoft_ohos:bizsocket_logger:1.0.0')
   implementation('com.gitee.chinasoft_ohos:bizsocket_tcp:1.0.0')
   implementation('com.gitee.chinasoft_ohos:bizsocket_core:1.0.0')
   ......  
}

 

在sdk6,DevEco Studio2.2 Beta1下项目可直接运行 如无法运行,删除项目.gradle,.idea,build,gradle,build.gradle文件, 并依据自己的版本创建新项目,将新项目的对应文件复制到根目录下

使用说明

一、 适用协议

如果想使用此库,客户端和服务器的通讯协议中必须要有命令号、包序列号这两个字段

  • 命令号代表请求类型,可以想象成http中url的作用
  • 包序列号是数据包的唯一索引,客户端发起请求时为数据包生成一个唯一索引,服务器返回请求对应的结果时把这个包序列号带回去

协议可以类似于下面这种:

cmd packetId contentLength content
int int int byte[]

也可以类似于下面这样的每个数据包都是一段json字符串,包与包之间用换行符分割

{"cmd": xxx , "packetId": xxx , ...... } 

 

数据包的创建是通过这两个抽象类PacketFactory、Packet,整个库的数据流转都是通过命令号、包序列号这两个字段来完成的,字段名、出现的位置以及形式不限,只要有这两个字段就适用此库

二、 配置BizSocket

sample中client与server之间的通讯协议是

length(int) cmd(int) seq(int) content(byte[])
数据包的总长度 命令号 数据包的唯一索引 报文体,可以想象成http协议中的body
  • 1、 首先需要创建一个数据包类继承自Packet
    public class SamplePacket extends Packet {
        static volatile int currentSeq = 0;
        public int length;
        public int cmd;
        public int seq;
        public String content;
        
        @Override
        public int getCommand() {
        	 //覆盖父类的抽象方法
            return cmd;
        }
    
        @Override
        public String getPacketID() {
            //覆盖父类的抽象方法
            return String.valueOf(seq);
        }
        
        //获取请求数据包byte[],写给服务器
        public byte[] toBytes() {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            BufferedSink bufferedSink = Okio.buffer(Okio.sink(bos));
            try {
                //包长 = 内容长度 + 包头固定的12个字节
                ByteString byteString = ByteString.encodeUtf8(content);
                bufferedSink.writeInt(byteString.size() + 12);
                bufferedSink.writeInt(cmd);
                bufferedSink.writeInt(seq);
                bufferedSink.write(byteString);
                bufferedSink.flush();
            } catch (IOException e) {
                e.fillInStackTrace();
            }
            return bos.toByteArray();
        }
    }​
  • 2、创建PacketFactory,主要用来从流中解析出server发给client的数据包
public class SamplePacketFactory extends PacketFactory {
    @Override
    public Packet getRequestPacket(Packet reusable,Request request) {
        return new SamplePacket(request.command(),request.body());
    }

    @Override
    public Packet getHeartBeatPacket(Packet reusable) {
        return new SamplePacket(SampleCmd.HEARTBEAT.getValue(), ByteString.encodeUtf8("{}"));
    }

    @Override
    public Packet getRemotePacket(Packet reusable,BufferedSource source) throws IOException {
      	 SamplePacket packet = new SamplePacket();
        packet.length = reader.readInt();
        packet.cmd = reader.readInt();
        packet.seq = reader.readInt();
        //减去协议头的12个字节长度
        packet.content = reader.readString(packet.length - 12, Charset.forName("utf-8"));
        return packet;
    }
}

 

  • 3、配置client
    public class SampleClient extends AbstractBizSocket {
        public SampleClient(Configuration configuration) {
            super(configuration);
        }
    
        @Override
        protected PacketFactory createPacketFactory() {
            return new SamplePacketFactory();
        }
    }​
  • 4、启动client,以j2se为例写一个main方法
public static void main(String[] args) {
        SampleClient client = new SampleClient(new Configuration.Builder()
                .host("127.0.0.1")
                .port(9103)
                .readTimeout(TimeUnit.SECONDS,30)
                .heartbeat(60)
                .build());

        client.getInterceptorChain().addInterceptor(new Interceptor() {
            @Override
            public boolean postRequestHandle(RequestContext context) throws Exception {
                LoggerUtil.i("发现一个请求postRequestHandle: " + context);
                return false;
            }

            @Override
            public boolean postResponseHandle(int command, Packet responsePacket) throws Exception {
                LoggerUtil.i("收到一个包postResponseHandle: " + responsePacket);
                return false;
            }
        });

        try {
            //连接
            client.connect();
            //启动断线重连
            client.getSocketConnection().bindReconnectionManager();
            //开启心跳
            client.getSocketConnection().startHeartBeat();
        } catch (Exception e) {
            e.fillInStackTrace();
        }

        //注册通知,接收服务端的推送
        client.subscribe(client, SampleCmd.NOTIFY_PRICE.getValue(), new ResponseHandler() {
            @Override
            public void sendSuccessMessage(int command, ByteString requestBody, Packet responsePacket) {
                LoggerUtil.i("cmd: " + command + " ,requestBody: " + requestBody + " responsePacket: " + responsePacket);
            }

            @Override
            public void sendFailureMessage(int command, Throwable error) {
                LoggerUtil.i(command + " ,err: " + error);
            }
        });

	//发起一对一请求
        String json = "{\"productId\" : \"1\",\"isJuan\" : \"0\",\"type\" : \"2\",\"sl\" : \"1\"}";
        client.request(new Request.Builder().command(SampleCmd.CREATE_ORDER.getValue()).utf8body(json).build(), new ResponseHandler() {
            @Override
            public void sendSuccessMessage(int command, ByteString requestBody, Packet responsePacket) {
                LoggerUtil.i("cmd: " + command + " ,requestBody: " + requestBody + " attach: " + " responsePacket: " + responsePacket);
            }

            @Override
            public void sendFailureMessage(int command, Throwable error) {
                LoggerUtil.i(command + " ,err: " + error);
            }
        });

	//如果想用rxjava的形式调用也是支持的,提供了类似于retrofit通过动态代理创建的service类来调用
        BizSocketRxSupport rxSupport = new BizSocketRxSupport.Builder()
                .requestConverter(new JSONRequestConverter())
                .responseConverter(new JSONResponseConverter())
                .bizSocket(client)
                .build();
        SampleService service = rxSupport.create(SampleService.class);

        JSONObject params = new JSONObject();
        try {
            params.put("pageSize","10000");
        } catch (JSONException e) {
            e.fillInStackTrace();
        }
        //rxjava范例,使用rxjava2需修改Subscriber
        service.queryOrderList(params).subscribe(new Subscriber<JSONObject>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(JSONObject jsonObject) {
                LoggerUtil.i("rx response: " + jsonObject);
            }
        });

	//阻塞主线程,防止程序退出,可以想象成ohos中的Looper类
        while (true) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.fillInStackTrace();
            }
        }
    }

测试信息

  • CodeCheck代码测试无异常
  • CloudTest代码测试无异常
  • 病毒安全检测通过
  • 当前版本demo功能与原组件基本无差异

版本迭代

  • 1.0.0

版权和许可信息

  • Apache 2.0

bizsocket-master.zip 252.8K 6次下载
已于2021-10-18 18:16:19修改
收藏
回复
举报
回复
    相关推荐