hylexus / jt-framework Goto Github PK
View Code? Open in Web Editor NEW基于Spring-Boot的JT-808协议服务端
Home Page: https://hylexus.github.io/jt-framework/
基于Spring-Boot的JT-808协议服务端
Home Page: https://hylexus.github.io/jt-framework/
准备把Gradle升级到7.3.3,报错:
Failed to apply plugin 'propdeps-maven'.
Could not create plugin of type 'PropDepsMavenPlugin'.
> Could not generate a decorated class for type PropDepsMavenPlugin.
> org/gradle/api/artifacts/maven/PomFilterContainer
在网上找propdeps-maven这个插件的资料也没有.
已经修改了两个地方:
中的
id 'maven'
已经被修改为: id 'maven-publish'
apply plugin: 'maven'
已经修改为:
apply plugin: 'maven-publish'
jt-808-server-spring-boot-stater 1.0.10-RELEASE
2021-01-07 10:27:14.382 ERROR 3135 --- [msg-processor-0] r.CustomReflectionBasedRequestMsgHandler : An unexpected exception occurred while invoke ExceptionHandler
java.lang.reflect.InvocationTargetException: null
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_265]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_265]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_265]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_265]
at io.github.hylexus.jt808.handler.impl.exception.ExceptionHandlerMethodExceptionHandler.handleException(ExceptionHandlerMethodExceptionHandler.java:47) ~[jt-808-server-support-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at io.github.hylexus.jt808.handler.impl.exception.DelegateExceptionHandler.handleException(DelegateExceptionHandler.java:55) ~[jt-808-server-support-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at io.github.hylexus.jt808.handler.impl.reflection.CustomReflectionBasedRequestMsgHandler.doProcess(CustomReflectionBasedRequestMsgHandler.java:80) ~[jt-808-server-support-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at io.github.hylexus.jt808.handler.AbstractMsgHandler.handleMsg(AbstractMsgHandler.java:36) [jt-808-server-support-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at io.github.hylexus.jt808.queue.listener.AbstractRequestMsgQueueListener.consumeMsg(AbstractRequestMsgQueueListener.java:65) [jt-808-server-support-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at io.github.hylexus.jt808.queue.listener.LocalEventBusListener.listen(LocalEventBusListener.java:42) [jt-808-server-support-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_265]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_265]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_265]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_265]
at com.google.common.eventbus.Subscriber.invokeSubscriberMethod(Subscriber.java:87) [guava-29.0-jre.jar:na]
at com.google.common.eventbus.Subscriber$SynchronizedSubscriber.invokeSubscriberMethod(Subscriber.java:144) [guava-29.0-jre.jar:na]
at com.google.common.eventbus.Subscriber$1.run(Subscriber.java:72) [guava-29.0-jre.jar:na]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_265]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_265]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_265]
Caused by: io.netty.channel.StacklessClosedChannelException: null
at io.netty.channel.AbstractChannel$AbstractUnsafe.write(Object, ChannelPromise)(Unknown Source) ~[netty-all-4.1.52.Final.jar:4.1.52.Final]
在@Jt808RequestMsgHandlerMapping
先调用openFeign里的方法(调用其它微服务)
再调用Jt808Session.sendMsgToClient就出错..
都是第一次发送出错。
第一次以后又都正常
终端参数项数据格式中参数值一项描述及要求:
若为多值参数,则消息中使用多个相同ID的参数项,如调度中心电话号码;
目前可能存在多msgId相同的情况,解析会出现被覆盖问题。
打成jar包之后,不能运行,提示没有main方法,什么原因呀
如下报文解析错误:
7E0200005B01234567891000110000000000000000020A3AAC067EAA2400000000000022083117155601040000014A30011D310100EB31000C00B28986049401208044782200060089FFFFFFFE000600C5FFFFFFE7000B00D801CC0090050FEC20C7000400B71D00947E
异常信息:
2022-09-06 11:31:29.978 [nioEventLoopGroup-5-1] ERROR jt-808.channel.dispatcher -
java.lang.IndexOutOfBoundsException: index: 12, length: 91 (expected: range(0, 25))
at io.netty.buffer.AbstractByteBuf.checkRangeBounds(AbstractByteBuf.java:1390)
at io.netty.buffer.AbstractByteBuf.checkIndex0(AbstractByteBuf.java:1397)
at io.netty.buffer.PooledSlicedByteBuf.slice(PooledSlicedByteBuf.java:106)
at io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgDecoder.decode(DefaultJt808MsgDecoder.java:57)
at io.github.hylexus.jt.jt808.support.netty.Jt808DispatchChannelHandlerAdapter.channelRead(Jt808DispatchChannelHandlerAdapter.java:53)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:327)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:314)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:435)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:279)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:995)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
2022-09-06 11:31:29.980 [nioEventLoopGroup-5-1] ERROR jt-808.request.decoder - Received unknown msg, msgId = 43556(0xaa24). ignore.
2022-09-06 11:31:29.980 [nioEventLoopGroup-5-1] ERROR jt-808.channel.dispatcher -
io.github.hylexus.jt.exception.JtIllegalStateException: Received unknown msg, msgId=43556
at io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgDecoder.lambda$parseMsgType$0(DefaultJt808MsgDecoder.java:91)
at java.base/java.util.Optional.orElseThrow(Optional.java:403)
at io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgDecoder.parseMsgType(DefaultJt808MsgDecoder.java:89)
at io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgDecoder.decode(DefaultJt808MsgDecoder.java:52)
at io.github.hylexus.jt.jt808.support.netty.Jt808DispatchChannelHandlerAdapter.channelRead(Jt808DispatchChannelHandlerAdapter.java:53)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:327)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:299)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:995)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
厂商解释:
"中间出现7E的情况这个是属于正常情况,而且设备上传的时候都是将中间出现的7E转义成7D02上传的,只是说你解析的时候需要转义回7E进行解析"
"数据都是实时发送,刚好数据发到有7E的字节那设备就会去进行转义,本来这个7E就算一个字节的,又不是一个没有的字节"
请问这种怎么处理?谢谢.
PassthroughPack 的byteCountOfMsgId实际定义的值为2,但是现在好像是默认值 1。 看看这块bean装箱有什么问题
请求报文:090000249782900021470379F02003160734200102010305300239B20546040000000005450400000000200316193912DB
@io.github.hylexus.jt.annotation.msg.req.extra.ExtraField(length=0, byteCountOfContentLength=1, byteCountMethod=getContentLength, byteCountOfMsgId=1, startIndex=11)
package com.ivyb2b.cesp.iot.dto.req;
import io.github.hylexus.jt.annotation.msg.req.Jt808ReqMsgBody;
import io.github.hylexus.jt.annotation.msg.req.basic.BasicField;
import io.github.hylexus.jt.annotation.msg.req.extra.ExtraField;
import io.github.hylexus.jt.annotation.msg.req.extra.ExtraMsgBody;
import io.github.hylexus.jt808.msg.RequestMsgBody;
import io.github.hylexus.jt808.msg.RequestMsgMetadata;
import io.github.hylexus.jt808.support.entity.scan.RequestMsgMetadataAware;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import static io.github.hylexus.jt.data.MsgDataType.*;
/**
* @Description 数据上行透传(0x0900)
* @Author wsy
* @Date 2020-03-11 14:04
* @Version 1.0
**/
@Data
@Accessors(chain = true)
@Jt808ReqMsgBody(msgType = 0x0900)
public class PassthroughPack implements RequestMsgBody, RequestMsgMetadataAware {
@ToString.Exclude
private RequestMsgMetadata requestMsgMetadata;
@Override
public void setRequestMsgMetadata(RequestMsgMetadata metadata) {
this.requestMsgMetadata = metadata;
}
/**
* 透传消息类型
* GNSS模块详细定位数据 0x00
* 道路运输证IC卡信息 0x0B
* 串口1透传 0x41
* 串口2透传 0x42
* 用户自定义透传 0xF0-0xF7
* OBD数据透传 0XF4
* 行车数据透传 0Xf8
* 用户自定义透传 0xF9-0xFF
*/
@BasicField(startIndex = 0, dataType = BYTE)
private int msgType;
@BasicField(startIndex = 1, dataType = BCD, length = 6)
private String time;
/**
* 数据类型
* 0x00:实时数据;
* 0x01:补传数据
*/
@BasicField(startIndex = 7, dataType = BYTE)
private int dataType;
/**
* 车辆类型
* 0x01:商用车;
* 0x02:乘用车
*/
@BasicField(startIndex = 8, dataType = BYTE)
private int vehicleType;
/**
* 消息子类
* 0x01:OBD数据流上报;
* 0x02:故障码数据上报;
* 0x03:告警数据及驾驶行为数据上报;
* 0x04:行程报告数据上报;
* 0x05:终端下位机日志数据上报;
* 0x06:CAN学习采集数据上传;
* 0x07:支持数据流ID列表上报;
* 0x08:支持车辆控制ID列表上报;
* 0x09:支持告警及驾驶行为数据ID列表上报
* 0x0A:车辆关键数据上传
* 0x0B:VIN码上报
* 0x0C:体检数据上报
* 0x0D:设备自检数据上报
*/
@BasicField(startIndex = 9, dataType = BYTE)
private int childMsgType;
/**
* 数据总数
*/
@BasicField(startIndex = 10, dataType = BYTE)
private int totalMsg;
/**
* 透传消息内容(子内容)
*/
@BasicField(startIndex = 11, dataType = BYTES,byteCountMethod = "getContentLength")
private byte[] content;
public int getContentLength() {
int totalLength = this.requestMsgMetadata.getHeader().getMsgBodyLength();
return totalLength - 11;
}
@ExtraField(
// 消息体中第11字节开始
startIndex = 11,
// 附加项长度用getExtraInfoLength返回值表示
byteCountMethod = "getContentLength"
)
private ExtraData extraData;
@Data
// 切记@ExtraMsgBody注解不能丢
@ExtraMsgBody(
byteCountOfMsgId = 2, // 消息Id用2个字节表示
byteCountOfContentLength = 1 // 附加项长度字段用1个字节表示
)
public static class ExtraData {
/**
* 电压 mV
*/
@ExtraField.NestedFieldMapping(msgId = 0x0530, dataType = WORD)
private int field0x0530;
/**
* 累计里程 km y=x/10;精度:0.1
*/
@ExtraField.NestedFieldMapping(msgId = 0x0546, dataType = DWORD)
private int field0x0546;
@ExtraField.NestedFieldMapping(msgId = 0x0545, dataType = DWORD)
private int field0x0545;
}
}
/**
* 符加信息
*/
@Data
public class ExtraInfo {
/**
* 信息ID
*/
@BasicField(startIndex = 0,dataType = BYTE)
private Short id;
/**
* 内容长度
*/
@BasicField(order = 1,startIndex = 1,dataType = BYTE)
private Short length;
/**
* 符加信息内容
*/
@BasicField(order = 2,startIndex = 2,dataType = BYTES,byteCountMethod = "getLength")
private byte[] rawBytes;
}
length的类型是BYTE,我用Short去接收,
byteCountMethod = "getLength" 会强转Short到Integer
2021-01-14 16:18:29.615 ERROR 7370 --- [ntLoopGroup-3-1] omReflectionBasedRequestMsgBodyConverter : java.lang.Short cannot be cast to java.lang.Integer
java.lang.ClassCastException: java.lang.Short cannot be cast to java.lang.Integer
at io.github.hylexus.jt.codec.decode.FieldDecoder.getLengthFromByteCountMethod(FieldDecoder.java:276) ~[jt-core-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at io.github.hylexus.jt.codec.decode.FieldDecoder.getBasicFieldLength(FieldDecoder.java:244) ~[jt-core-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at io.github.hylexus.jt.codec.decode.FieldDecoder.processListDataType(FieldDecoder.java:180) ~[jt-core-1.0.10-RELEASE.jar:1.0.10-RELEASE]
出错代码定位
private <T> Integer getLengthFromByteCountMethod(T instance, Method lengthMethod)
throws IllegalAccessException, InvocationTargetException {
return (Integer) lengthMethod.invoke(instance);
}
我们公司现在还是用的JDK 8,这个是否支持?如果不支持,需要做哪些工作来适配?
终端参数结果返回的是列表,但字段没有固定长度,请问应该怎么解析?谢谢.
比如0x0200指令,针对苏标和粤标采用不同的方法去处理,可以做到解析2013苏标、2019苏标、2013粤标和2019粤标
nested exception is io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1] with root cause
io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
at io.netty.util.internal.ReferenceCountUpdater.toLiveRealRefCnt(ReferenceCountUpdater.java:74)
at io.netty.util.internal.ReferenceCountUpdater.release(ReferenceCountUpdater.java:138)
at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:100)
at io.netty.buffer.CompositeByteBuf.addComponent0(CompositeByteBuf.java:307)
at io.netty.buffer.CompositeByteBuf.addComponent(CompositeByteBuf.java:265)
at io.netty.buffer.CompositeByteBuf.addComponent(CompositeByteBuf.java:222)
at io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgEncoder.buildPackage(DefaultJt808MsgEncoder.java:93)
at io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgEncoder.encode(DefaultJt808MsgEncoder.java:54)
at io.github.hylexus.jt.jt808.spec.impl.DefaultJt808CommandSender.encode(DefaultJt808CommandSender.java:29)
at io.github.hylexus.jt.jt808.spec.impl.AbstractJt808CommandSender.sendCommandAndWaitingForReply(AbstractJt808CommandSender.java:35)
idea 201801版本 无法编译该项目
错误:
java.lang.AbstractMethodError: org.jetbrains.plugins.gradle.tooling.util.ModuleComponentIdentifierImpl.getModuleIdentifier()Lorg/gradle/api/artifacts/ModuleIdentifier;
gradle降级到 4.10.3-bin也会报另外的错
Could not get unknown property 'archiveClassifier' for task ':jt-808-server-spring-boot-stater:sourcesJar' of type org.gradle.api.tasks.bundling.Jar.
archiveClassifier应该5.0+的属性。
<dependency> //依赖版本
<groupId>io.github.hylexus.jt</groupId>
<artifactId>jt-808-server-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
具体报错日志
2024-01-15T00:50:42.120+08:00 ERROR 1786 --- [ntLoopGroup-4-4] io.netty.util.ResourceLeakDetector : LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
#1:
io.github.hylexus.jt.jt808.support.utils.JtProtocolUtils.release(JtProtocolUtils.java:214)
io.github.hylexus.jt.jt808.support.netty.Jt808DispatchChannelHandlerAdapter.channelRead(Jt808DispatchChannelHandlerAdapter.java:50)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:425)
io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)
io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:66)
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
java.base/java.lang.Thread.run(Thread.java:1583)
#2:
io.netty.buffer.AdvancedLeakAwareByteBuf.getByte(AdvancedLeakAwareByteBuf.java:155)
io.github.hylexus.jt.utils.HexStringUtils.encodeHex(HexStringUtils.java:23)
io.github.hylexus.jt.utils.HexStringUtils.byteBufToString(HexStringUtils.java:58)
io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgDecoder.decode(DefaultJt808MsgDecoder.java:47)
io.github.hylexus.jt.jt808.support.dispatcher.impl.SimpleJt808RequestProcessor.processJt808Request(SimpleJt808RequestProcessor.java:43)
io.github.hylexus.jt.jt808.support.netty.Jt808DispatchChannelHandlerAdapter.channelRead(Jt808DispatchChannelHandlerAdapter.java:48)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:425)
io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)
io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:66)
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
java.base/java.lang.Thread.run(Thread.java:1583)
#3:
io.netty.buffer.AdvancedLeakAwareByteBuf.getByte(AdvancedLeakAwareByteBuf.java:155)
io.github.hylexus.jt.utils.HexStringUtils.encodeHex(HexStringUtils.java:23)
io.github.hylexus.jt.utils.HexStringUtils.byteBufToString(HexStringUtils.java:58)
io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgDecoder.decode(DefaultJt808MsgDecoder.java:42)
io.github.hylexus.jt.jt808.support.dispatcher.impl.SimpleJt808RequestProcessor.processJt808Request(SimpleJt808RequestProcessor.java:43)
io.github.hylexus.jt.jt808.support.netty.Jt808DispatchChannelHandlerAdapter.channelRead(Jt808DispatchChannelHandlerAdapter.java:48)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:425)
io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)
io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:66)
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
java.base/java.lang.Thread.run(Thread.java:1583)
#4:
Hint: 'Jt808NettyHandlerAdapter' will handle the message from this point.
io.netty.channel.DefaultChannelPipeline.touch(DefaultChannelPipeline.java:116)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:417)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:333)
io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:454)
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
java.base/java.lang.Thread.run(Thread.java:1583)
Created at:
io.netty.buffer.SimpleLeakAwareByteBuf.unwrappedDerived(SimpleLeakAwareByteBuf.java:144)
io.netty.buffer.SimpleLeakAwareByteBuf.readRetainedSlice(SimpleLeakAwareByteBuf.java:67)
io.netty.buffer.AdvancedLeakAwareByteBuf.readRetainedSlice(AdvancedLeakAwareByteBuf.java:108)
io.netty.handler.codec.DelimiterBasedFrameDecoder.decode(DelimiterBasedFrameDecoder.java:270)
io.netty.handler.codec.DelimiterBasedFrameDecoder.decode(DelimiterBasedFrameDecoder.java:215)
io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:529)
io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:468)
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
java.base/java.lang.Thread.run(Thread.java:1583)
: 7 leak records were discarded because they were duplicates
: 140 leak records were discarded because the leak record count is targeted to 4. Use system property io.netty.leakDetection.targetRecords to increase the limit.
如题。源码有startIndexMethod这个实现,但是没有找到相关的使用方法。
消息下发功能太简单
1、消息下发可直接下发对象到终端(自动对象转换HEX)
2、消息下发应答处理-应可直接转换为定义的resquest对象。
3、应答消息可考虑放置redis等中,考虑下集群部署问题。
/**
* 符加信息
*/
@Data
public class ExtraInfo {
/**
* 信息ID
*/
@BasicField(startIndex = 0,dataType = BYTE)
private Integer id;
/**
* 内容长度
*/
@BasicField(order = 1,startIndex = 1,dataType = BYTE)
private Integer length;
/**
* 符加信息内容
*/
@BasicField(order = 2,startIndex = 2,dataType = BYTES,byteCountMethod = "getLength")
private byte[] rawBytes;
/**
* rawBytes转成具体内容保存在这里
*/
private Object content;
}
private object content
增加这个属性就会出null Error
2021-01-14 16:05:12.765 ERROR 7186 --- [ntLoopGroup-3-1] omReflectionBasedRequestMsgBodyConverter : null
java.lang.NullPointerException: null
at io.github.hylexus.jt.codec.decode.FieldDecoder.processListDataType(FieldDecoder.java:180) ~[jt-core-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at io.github.hylexus.jt.codec.decode.FieldDecoder.processBasicFieldInternal(FieldDecoder.java:132) ~[jt-core-1.0.10-RELEASE.jar:1.0.10-RELEASE]
at io.github.hylexus.jt.codec.decode.FieldDecoder.processBasicField(FieldDecoder.java:98) ~[jt-core-1.0.10-RELEASE.jar:1.0.10-RELEASE]
出错代码定位
类:io.github.hylexus.jt.codec.decode.FieldDecoder
方法:processListDataType
final BasicField itemAnnotation = itemFieldMetadata.getAnnotation(BasicField.class);
遍历到content时,itemAnnotion 是null
`
package io.github.hylexus.jt808.dispatcher;
import io.github.hylexus.jt.data.msg.MsgType;
import io.github.hylexus.jt808.converter.RequestMsgBodyConverter;
import io.github.hylexus.jt808.msg.RequestMsgBody;
import io.github.hylexus.jt808.msg.RequestMsgWrapper;
import io.github.hylexus.jt808.support.RequestMsgBodyConverterMapping;
import lombok.extern.slf4j.Slf4j;
import java.util.Optional;
/**
@author hylexus
createdAt 2019/1/24
**/
@slf4j
public abstract class AbstractRequestMsgDispatcher implements RequestMsgDispatcher {
private RequestMsgBodyConverterMapping msgConverterMapping;
public AbstractRequestMsgDispatcher(RequestMsgBodyConverterMapping msgConverterMapping) {
this.msgConverterMapping = msgConverterMapping;
}
public void doDispatch(RequestMsgWrapper wrapper) throws Exception {
final Optional<RequestMsgBody> subMsg = tryParseMsgBody(wrapper);
if (!subMsg.isPresent()) {
return;
}
wrapper.setBody(subMsg.get());
this.doBroadcast(wrapper);
}
private Optional tryParseMsgBody(RequestMsgWrapper wrapper) {
final MsgType msgType = wrapper.getMetadata().getMsgType();
final Optional<RequestMsgBodyConverter<? extends RequestMsgBody>> converterInfo = this.msgConverterMapping.getConverter(msgType);
if (!converterInfo.isPresent()) {
log.error("No [MsgConverter] found for msgType {}", msgType);
return Optional.empty();
}
final RequestMsgBodyConverter<? extends RequestMsgBody> msgBodyConverter = converterInfo.get();
final Optional<? extends RequestMsgBody> subMsg = msgBodyConverter.convert2Entity(wrapper.getMetadata());
if (!subMsg.isPresent()) {
log.debug("[MsgConverter] return empty(). converter:{}", msgBodyConverter.getClass());
return Optional.empty();
}
final RequestMsgBody requestMsgBody = subMsg.get();
return Optional.of(requestMsgBody);
}
public abstract void doBroadcast(RequestMsgWrapper wrapper) throws Exception;
}
`
DWORD,如果用Integer去接收,超过0x7f_ff_ff_ff的,Interger
就会显示负数。Integer的最大值是0x7f_ff_ff_ff
虽然底层是一样的bit.但显示出来就是错误的。可以用Long去接收
package io.github.hylexus.jt.utils;
import io.github.hylexus.jt.config.JtProtocolConstant;
import io.github.hylexus.jt.exception.MsgEscapeException;
import io.github.hylexus.oaks.utils.Bytes;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* @author hylexus
* createdAt 2019/1/28
**/
@Slf4j
public class ProtocolUtils {
public static byte calculateCheckSum4Jt808(byte[] bs, int start, int end) {
byte sum = bs[start];
for (int i = start + 1; i < end; i++) {
sum ^= bs[i];
}
return sum;
}
public static byte[] doEscape4ReceiveJt808Msg(byte[] bs, int start, int end) throws Exception {
if (start < 0 || end > bs.length) {
throw new ArrayIndexOutOfBoundsException("doEscape4Receive error : index out of bounds(start=" + start
+ ",end=" + end + ",bytes length=" + bs.length + ")");
}
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
int i = 0;
for (; i < start; i++) {
outputStream.write(bs[i]);
}
// 最后一个字节不应该是7d,否则就是编码错误
for (; i < end - 1; i++) {
if (bs[i] == 0x7d && bs[i + 1] == 0x01) {
outputStream.write(0x7d);
i++;
} else if (bs[i] == 0x7d && bs[i + 1] == 0x02) {
outputStream.write(0x7e);
i++;
} else {
outputStream.write(bs[i]);
}
}
// https://github.com/hylexus/jt-framework/issues/17
for (; i < bs.length; i++) {
outputStream.write(bs[i]);
}
return outputStream.toByteArray();
} catch (IOException e) {
throw new MsgEscapeException(e);
}
}
public static byte[] doEscape4SendJt808Msg(byte[] bs, int start, int end) throws IOException {
if (start < 0 || end > bs.length) {
throw new ArrayIndexOutOfBoundsException("doEscape4Send error : index out of bounds(start=" + start
+ ",end=" + end + ",bytes length=" + bs.length + ")");
}
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
for (int i = 0; i < start; i++) {
outputStream.write(bs[i]);
}
for (int i = start; i <= end; i++) {
if (bs[i] == 0x7e) {
outputStream.write(0x7d);
outputStream.write(0x02);
}else if (bs[i] == 0x7d){
// 应该添加此条件
//https://github.com/hylexus/jt-framework/issues/26
outputStream.write(0x7d);
outputStream.write(0x01);
} else {
outputStream.write(bs[i]);
}
}
// https://github.com/hylexus/jt-framework/issues/17
for (int i = end + 1; i < bs.length; i++) {
outputStream.write(bs[i]);
}
return outputStream.toByteArray();
} catch (IOException e) {
throw new MsgEscapeException(e);
}
}
public static String bytes2String(byte[] bytes, int start, int length) {
return bytes2String(bytes, start, length, null);
}
public static String bytes2String(byte[] bytes, int start, int length, String defaultVal) {
try {
return new String(Bytes.subSequence(bytes, start, length), JtProtocolConstant.JT_808_STRING_ENCODING);
} catch (Exception e) {
log.error(e.getMessage(), e);
return defaultVal;
}
}
public static byte[] byteBufToByteArray(ByteBuf buf, int length) {
byte[] tmp = new byte[length];
buf.readBytes(tmp);
return tmp;
}
}
设置心跳值后,主动发送消息,服务端才会在指定时间间隔断掉连接,如果不发消息,连接就会一直保持,成为僵尸连接
handler-scan的默认配置下,多了一级base-packages
大佬, 有没有Maven版本的?或者qq群来学习?
HeatBeatHandler缺少 @ChannelHandler.Sharable 注解
例如二进制串1234会被解析成字符串1234,而123A则会被解析成12310
您好,框架解析了报警标志为数字,请问怎么知道数字对应的具体含义呢?比如: 4096 , 谢谢!
public class BuiltinMsg0200V2013 {
// (1). byte[0,4) DWORD 报警标志
@RequestField(order = 1, startIndex = 0, dataType = DWORD)
private long alarmFlag;
求教 消息体 加密如何处理
消息头,消息属性中的 第10位,11位,12位 为 010 时,表示消息体经过SM4算法加密
对象中没有E3 还有F3也无法获取到值。
debug时候 循环是能取到 E3 还有F3的值的。貌似没有set到对象中。 附件是我的 LocationUploadRequestMsgBody 类
7E020000C705019500000200B700000000000410000157B48906CA55BE00400000000020030400010401040000000002020000030200002504000000002A0200002B040000000030011E310108E306006404EC0199F37D010002020000000302000000040231380005040000000000060200000007020000000801000009020000000B020000000C020000000D020000000E0100000F0100005204000000000100020000010104000000000102020000010304000000000104020000010C020000010D020000010E020000010F02FFD801100204EE1B7E
package com.ivyb2b.cesp.iot.entity.req;
import io.github.hylexus.jt.annotation.msg.req.Jt808ReqMsgBody;
import io.github.hylexus.jt.annotation.msg.req.basic.BasicField;
import io.github.hylexus.jt.annotation.msg.req.extra.ExtraField;
import io.github.hylexus.jt.annotation.msg.req.extra.ExtraMsgBody;
import io.github.hylexus.jt.annotation.msg.req.slice.SlicedFrom;
import io.github.hylexus.jt.annotation.msg.req.slice.SplittableField;
import io.github.hylexus.jt.data.converter.req.entity.LngLatReqMsgFieldConverter;
import io.github.hylexus.jt808.msg.RequestMsgBody;
import io.github.hylexus.jt808.msg.RequestMsgMetadata;
import io.github.hylexus.jt808.support.entity.scan.RequestMsgMetadataAware;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import static io.github.hylexus.jt.data.MsgDataType.*;
/**
* @author hylexus
* Created At 2020-01-29 12:03 下午
*/
@Data
@Accessors(chain = true)
@Jt808ReqMsgBody(msgType = 0x0200)
public class LocationUploadRequestMsgBody implements RequestMsgBody, RequestMsgMetadataAware {
@ToString.Exclude
private RequestMsgMetadata requestMsgMetadata;
@Override
public void setRequestMsgMetadata(RequestMsgMetadata metadata) {
this.requestMsgMetadata = metadata;
}
// 报警标志
@BasicField(startIndex = 0, dataType = DWORD)
private int alarmFlag;
// 状态
@BasicField(startIndex = 4, dataType = DWORD)
@SplittableField(splitPropertyValueIntoNestedBeanField = "statusInfo")
private int status;
private LocationUploadStatus statusInfo;
@BasicField(startIndex = 4, dataType = BYTES, length = 4)
private byte[] statusBytes;
// 将上面的 status 字段的第0位取出转为 int 类型
@SlicedFrom(sourceFieldName = "status", bitIndex = 0)
private int accIntStatus;
// 将上面的 status 字段的第0位取出转为 boolean 类型
@SlicedFrom(sourceFieldName = "status", bitIndex = 0)
private Boolean accBooleanStatus;
// 0 北纬;1 南纬
// 将上面的 status 字段的第2位取出转为 int 类型
@SlicedFrom(sourceFieldName = "status", bitIndex = 2)
private int latType;
// 纬度(尚未除以 10^6)
@BasicField(startIndex = 8, dataType = DWORD)
private Integer intLat;
// 纬度(使用转换器除以10^6转为Double类型)
@BasicField(startIndex = 8, dataType = DWORD, customerDataTypeConverterClass = LngLatReqMsgFieldConverter.class)
private Double lat;
// 经度(尚未除以 10^6)
@BasicField(startIndex = 12, dataType = DWORD)
private Integer intLng;
// 经度(使用转换器除以10^6转为Double类型)
@BasicField(startIndex = 12, dataType = DWORD, customerDataTypeConverterClass = LngLatReqMsgFieldConverter.class)
private Double lng;
// 高度
@BasicField(startIndex = 16, dataType = WORD)
private Integer height;
// 速度
@BasicField(startIndex = 18, dataType = WORD)
private int speed;
// 方向
@BasicField(startIndex = 20, dataType = WORD)
private Integer direction;
@BasicField(startIndex = 22, dataType = BCD, length = 6)
private String time;
@ExtraField(
// 消息体中第28字节开始
startIndex = 28,
// 附加项长度用getExtraInfoLength返回值表示
byteCountMethod = "getExtraInfoLength"
)
private ExtraInfo extraInfo;
public int getExtraInfoLength() {
int totalLength = this.requestMsgMetadata.getHeader().getMsgBodyLength();
return totalLength - 28;
}
@Data
// 切记@ExtraMsgBody注解不能丢
@ExtraMsgBody(
byteCountOfMsgId = 1, // 消息Id用1个字节表示
byteCountOfContentLength = 1 // 附加项长度字段用1个字节表示
)
public static class ExtraInfo {
@ExtraField.NestedFieldMapping(msgId = 0x01, dataType = DWORD)
private int field0x01;
@ExtraField.NestedFieldMapping(msgId = 0x02, dataType = WORD)
private int field0x02;
@ExtraField.NestedFieldMapping(msgId = 0x03, dataType = WORD)
private int field0x03;
@ExtraField.NestedFieldMapping(msgId = 0x25, dataType = DWORD)
private int field0x25;
@ExtraField.NestedFieldMapping(msgId = 0x2A, dataType = WORD)
private int field0x2A;
@ExtraField.NestedFieldMapping(msgId = 0x2B, dataType = DWORD)
private int field0x2B;
@ExtraField.NestedFieldMapping(msgId = 0x30, dataType = BYTE)
private byte field0x30;
@ExtraField.NestedFieldMapping(msgId = 0x31, dataType = BYTE)
private byte field0x31;
@ExtraField.NestedFieldMapping(msgId = 0xE3, dataType = BCD)
private String field0xE3;
@ExtraField.NestedFieldMapping(msgId = 0xF3, dataType = BYTES,isNestedExtraField=true)
private DrivingData drivingData;
// @ExtraField.NestedFieldMapping(msgId = 0xD1, dataType = BYTE)
// private int field0xD1;
//
// @ExtraField.NestedFieldMapping(msgId = 0xD2, dataType = BYTE)
// private int field0xD2;
//
// @ExtraField.NestedFieldMapping(msgId = 0xD3, dataType = WORD)
// private int field0xD3;
//
// @ExtraField.NestedFieldMapping(msgId = 0xD4, dataType = WORD)
// private int field0xD4;
//
// @ExtraField.NestedFieldMapping(msgId = 0xD5, dataType = WORD)
// private int field0xD5;
//
// @ExtraField.NestedFieldMapping(msgId = 0xD6, dataType = BYTES)
// private byte field0xD6;
}
@Data
// 切记@ExtraMsgBody注解不能丢
@ExtraMsgBody(
byteCountOfMsgId = 2, // 消息Id用1个字节表示
byteCountOfContentLength = 1 // 附加项长度字段用1个字节表示
)
public static class DrivingData{
@ExtraField.NestedFieldMapping(msgId = 0x0002, dataType = WORD)
private int field0x0002;
@ExtraField.NestedFieldMapping(msgId = 0x0003, dataType = WORD)
private int field0x0003;
@ExtraField.NestedFieldMapping(msgId = 0x0004, dataType = WORD)
private int field0x0004;
@ExtraField.NestedFieldMapping(msgId = 0x0005, dataType = DWORD)
private int field0x0005;
@ExtraField.NestedFieldMapping(msgId = 0x0006, dataType = WORD)
private int field0x0006;
@ExtraField.NestedFieldMapping(msgId = 0x0007, dataType = WORD)
private int field0x0007;
@ExtraField.NestedFieldMapping(msgId = 0x0008, dataType = BYTE)
private int field0x0008;
@ExtraField.NestedFieldMapping(msgId = 0x0009, dataType = WORD)
private int field0x0009;
@ExtraField.NestedFieldMapping(msgId = 0x000B, dataType = WORD)
private int field0x000B;
@ExtraField.NestedFieldMapping(msgId = 0x000C, dataType = WORD)
private int field0x000C;
@ExtraField.NestedFieldMapping(msgId = 0x000D, dataType = WORD)
private int field0x000D;
@ExtraField.NestedFieldMapping(msgId = 0x000E, dataType = BYTE)
private int field0x000E;
@ExtraField.NestedFieldMapping(msgId = 0x000F, dataType = BYTE)
private int field0x000F;
@ExtraField.NestedFieldMapping(msgId = 0x0052, dataType = DWORD)
private int field0x0052;
@ExtraField.NestedFieldMapping(msgId = 0x0100, dataType = WORD)
private int field0x0100;
@ExtraField.NestedFieldMapping(msgId = 0x0101, dataType = DWORD)
private int field0x0101;
@ExtraField.NestedFieldMapping(msgId = 0x0102, dataType = WORD)
private int field0x0102;
@ExtraField.NestedFieldMapping(msgId = 0x0103, dataType = DWORD)
private int field0x0103;
@ExtraField.NestedFieldMapping(msgId = 0x0104, dataType = WORD)
private int field0x0104;
@ExtraField.NestedFieldMapping(msgId = 0x010C, dataType = WORD)
private int field0x010C;
@ExtraField.NestedFieldMapping(msgId = 0x010D, dataType = WORD)
private int field0x010D;
@ExtraField.NestedFieldMapping(msgId = 0x010E, dataType = WORD)
private int field0x010E;
@ExtraField.NestedFieldMapping(msgId = 0x010F, dataType = WORD)
private int field0x010F;
@ExtraField.NestedFieldMapping(msgId = 0x0110, dataType = WORD)
private int field0x0110;
}
@Data
public static class LocationUploadStatus {
@SplittableField.BitAt(bitIndex = 0)
private boolean accStatus; // acc开?
@SplittableField.BitAt(bitIndex = 1)
private int bit1; //1:定位, 0:未定义
@SplittableField.BitAt(bitIndex = 2)
private Boolean isSouthLat;// 是否南纬?
@SplittableField.BitAt(bitIndex = 3)
private Integer lngType;
// 将第0位和第1位同时取出并转为int
// 在此处无实际意义,只是演示可以这么使用
@SplittableField.BitAtRange(startIndex = 0, endIndex = 1)
private int bit0to1;
}
}
public static byte[] doEscape4ReceiveJt808Msg(byte[] bs, int start, int end) throws Exception {
if (start < 0 || end > bs.length) {
throw new ArrayIndexOutOfBoundsException("doEscape4Receive error : index out of bounds(start=" + start
+ ",end=" + end + ",bytes length=" + bs.length + ")");
}
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
for (int i = 0; i < start; i++) {
outputStream.write(bs[i]);
}
for (int i = start; i < end - 1; i++) {
if (bs[i] == 0x7d && bs[i + 1] == 0x01) {
outputStream.write(0x7d);
i++;
} else if (bs[i] == 0x7d && bs[i + 1] == 0x02) {
outputStream.write(0x7e);
i++;
} else {
outputStream.write(bs[i]);
}
}
if (bs[end - 1] == 0x7d && bs[end] == 0x01) {
outputStream.write(0x7d);
} else if (bs[end - 1] == 0x7d && bs[end] == 0x02) {
outputStream.write(0x7e);
} else {
for (int i = end - 1; i < bs.length; i++) {
outputStream.write(bs[i]);
}
}
return outputStream.toByteArray();
}
}
JT/T 808有2011、2013、2019多个版本,目前项目支持哪些版本?建议在文档增加下协议配套说明
[ ERROR] [2022-03-20 15:01:33.939] io.netty.util.ResourceLeakDetector [319] [808-msg-processor-13]- LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
Created at:
io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:385)
io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:187)
io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:178)
io.netty.buffer.AbstractByteBufAllocator.ioBuffer(AbstractByteBufAllocator.java:139)
io.netty.channel.DefaultMaxMessagesRecvByteBufAllocator$MaxMessageHandle.allocate(DefaultMaxMessagesRecvByteBufAllocator.java:114)
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:150)
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
java.base/java.lang.Thread.run(Thread.java:834)
[ ERROR] [2022-03-20 15:01:33.941] io.netty.util.ResourceLeakDetector [319] [808-msg-processor-13]- LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
Created at:
io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:385)
io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:187)
io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:173)
io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:107)
io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgBytesProcessor.doEscapeForReceive(DefaultJt808MsgBytesProcessor.java:53)
io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgDecoder.decode(DefaultJt808MsgDecoder.java:44)
io.github.hylexus.jt.jt808.support.netty.Jt808DispatchChannelHandlerAdapter.channelRead(Jt808DispatchChannelHandlerAdapter.java:53)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
java.base/java.lang.Thread.run(Thread.java:834)
[ ERROR] [2022-03-20 15:01:33.943] io.netty.util.ResourceLeakDetector [319] [808-msg-processor-13]- LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
Created at:
io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:385)
io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:187)
io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:173)
io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:107)
io.github.hylexus.jt.jt808.support.annotation.codec.Jt808AnnotationBasedEncoder.encodeMsgBody(Jt808AnnotationBasedEncoder.java:86)
io.github.hylexus.jt.jt808.support.annotation.codec.Jt808AnnotationBasedEncoder.encodeAndWriteToResponse(Jt808AnnotationBasedEncoder.java:53)
io.github.hylexus.jt.jt808.support.dispatcher.handler.result.Jt808ResponseBodyHandlerResultHandler.doHandleResult(Jt808ResponseBodyHandlerResultHandler.java:57)
io.github.hylexus.jt.jt808.support.dispatcher.handler.result.Jt808ResponseBodyHandlerResultHandler.handleResult(Jt808ResponseBodyHandlerResultHandler.java:45)
io.github.hylexus.jt.jt808.support.dispatcher.Jt808DispatcherHandler.handleResult(Jt808DispatcherHandler.java:121)
io.github.hylexus.jt.jt808.support.dispatcher.Jt808DispatcherHandler.processHandlerResult(Jt808DispatcherHandler.java:96)
io.github.hylexus.jt.jt808.support.dispatcher.Jt808DispatcherHandler.handleRequest(Jt808DispatcherHandler.java:62)
io.github.hylexus.jt.jt808.spec.impl.request.queue.AbstractJt808RequestMsgQueueListener.consumeMsg(AbstractJt808RequestMsgQueueListener.java:56)
io.github.hylexus.jt.jt808.spec.impl.request.queue.LocalEventBusListener.listen(LocalEventBusListener.java:39)
jdk.internal.reflect.GeneratedMethodAccessor39.invoke(Unknown Source)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.base/java.lang.reflect.Method.invoke(Method.java:566)
com.google.common.eventbus.Subscriber.invokeSubscriberMethod(Subscriber.java:91)
com.google.common.eventbus.Subscriber$SynchronizedSubscriber.invokeSubscriberMethod(Subscriber.java:150)
com.google.common.eventbus.Subscriber$1.run(Subscriber.java:76)
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
java.base/java.lang.Thread.run(Thread.java:834)
[ ERROR] [2022-03-20 15:01:33.947] io.netty.util.ResourceLeakDetector [319] [808-msg-processor-13]- LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
Created at:
io.netty.buffer.AbstractByteBufAllocator.compositeDirectBuffer(AbstractByteBufAllocator.java:223)
io.netty.buffer.AbstractByteBufAllocator.compositeDirectBuffer(AbstractByteBufAllocator.java:218)
io.netty.buffer.AbstractByteBufAllocator.compositeBuffer(AbstractByteBufAllocator.java:193)
io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgEncoder.buildPackage(DefaultJt808MsgEncoder.java:91)
io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgEncoder.encode(DefaultJt808MsgEncoder.java:54)
io.github.hylexus.jt.jt808.support.dispatcher.handler.result.Jt808ResponseBodyHandlerResultHandler.doHandleResult(Jt808ResponseBodyHandlerResultHandler.java:59)
io.github.hylexus.jt.jt808.support.dispatcher.handler.result.Jt808ResponseBodyHandlerResultHandler.handleResult(Jt808ResponseBodyHandlerResultHandler.java:45)
io.github.hylexus.jt.jt808.support.dispatcher.Jt808DispatcherHandler.handleResult(Jt808DispatcherHandler.java:121)
io.github.hylexus.jt.jt808.support.dispatcher.Jt808DispatcherHandler.processHandlerResult(Jt808DispatcherHandler.java:96)
io.github.hylexus.jt.jt808.support.dispatcher.Jt808DispatcherHandler.handleRequest(Jt808DispatcherHandler.java:62)
io.github.hylexus.jt.jt808.spec.impl.request.queue.AbstractJt808RequestMsgQueueListener.consumeMsg(AbstractJt808RequestMsgQueueListener.java:56)
io.github.hylexus.jt.jt808.spec.impl.request.queue.LocalEventBusListener.listen(LocalEventBusListener.java:39)
jdk.internal.reflect.GeneratedMethodAccessor39.invoke(Unknown Source)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.base/java.lang.reflect.Method.invoke(Method.java:566)
com.google.common.eventbus.Subscriber.invokeSubscriberMethod(Subscriber.java:91)
com.google.common.eventbus.Subscriber$SynchronizedSubscriber.invokeSubscriberMethod(Subscriber.java:150)
com.google.common.eventbus.Subscriber$1.run(Subscriber.java:76)
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
java.base/java.lang.Thread.run(Thread.java:834)
[ ERROR] [2022-03-20 15:01:33.951] io.netty.util.ResourceLeakDetector [319] [808-msg-processor-13]- LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
Created at:
io.netty.buffer.AbstractByteBufAllocator.compositeDirectBuffer(AbstractByteBufAllocator.java:223)
io.netty.buffer.AbstractByteBufAllocator.compositeBuffer(AbstractByteBufAllocator.java:201)
io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgBytesProcessor.doEscapeForReceive(DefaultJt808MsgBytesProcessor.java:66)
io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgDecoder.decode(DefaultJt808MsgDecoder.java:44)
io.github.hylexus.jt.jt808.support.netty.Jt808DispatchChannelHandlerAdapter.channelRead(Jt808DispatchChannelHandlerAdapter.java:53)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
java.base/java.lang.Thread.run(Thread.java:834)
希望这块儿的功能可做成可配置的,或者是直接省略,因为所有项目不见得会接入所有消息,是收到除了框架内定义的MsgType以外的类型时会一直抛异常,导致日志都非常难看。
Hi there this is the author of vuepress-theme-hope. though vuepress hope logo is used in demo, but I would suggest you to replace it in production. Maybe you can create a logo of your own.
目前 @RequestField
和 @ResponseField
注解都有 order
属性来保证序列化和反序列化时属性的顺序。
能否安全地去掉这个 “看似多余” 的属性?
没找到这方面的官方文档说明。
参考 java-reflection-getting-fields-and-methods-in-declaration-order)
你好,maven仓库找不到1.0.3版本
JDK: 17
实体类定义:
import io.github.hylexus.jt.jt808.support.annotation.msg.resp.Jt808ResponseBody;
import io.github.hylexus.jt.jt808.support.annotation.msg.resp.ResponseField;
import io.github.hylexus.jt.jt808.support.data.MsgDataType;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
import static io.github.hylexus.jt.jt808.support.data.MsgDataType.*;
/**
* Created At 2019-10-16 10:43 下午
*
* <p>Ref: https://github.com/hylexus/jt-framework/blob/master/samples/jt-808-server-sample-debug/
* src/main/java/io/github/hylexus/jt/jt808/samples/debug/entity/resp/RespTerminalSettings.java
*
* @author hylexus
*/
@Data
@Accessors(chain = true)
@Jt808ResponseBody(msgId = 0x8103, desc = "设置终端参数")
public class RespTerminalSettings {
@ResponseField(order = 1, dataType = BYTE)
private int totalParamCount;
@ResponseField(order = 2, dataType = MsgDataType.LIST)
private List<ParamItem> paramList;
@Data
@Accessors(chain = true)
public static class ParamItem {
@ResponseField(order = 1, dataType = DWORD)
private int msgId;
@ResponseField(order = 2, dataType = BYTE)
private int bytesCountOfContentLength;
@ResponseField(order = 3, dataType = BYTES)
private ByteBuf msgContent;
public ParamItem() {}
public ParamItem(int msgId, ByteBuf msgContent) {
this.msgId = msgId;
this.msgContent = msgContent;
this.bytesCountOfContentLength = msgContent.readableBytes();
}
}
}
调用:
/**
* 设置终端参数
*
* @param terminalId 终端id,第一位为0的手机号
* @param msgId 消息id
* @param msgValue 消息内容(类型需要与消息id对应的一致)
*/
public void terminalParamSetting(String terminalId, int msgId, Object msgValue) {
final RespTerminalSettings param = new RespTerminalSettings();
var msgVal = ByteBufAllocator.DEFAULT.buffer();
final int carColorSet = 0x0084;
if (TERMINAL_SET_TYPE_LIST.contains(msgId)) {
msgVal = ByteBufAllocator.DEFAULT.buffer().writeBytes(String.valueOf(msgValue).getBytes());
} else if (msgId == carColorSet) {
msgVal =
ByteBufAllocator.DEFAULT.buffer().writeByte(Integer.parseInt(String.valueOf(msgValue)));
} else {
msgVal =
ByteBufAllocator.DEFAULT.buffer().writeInt(Integer.parseInt(String.valueOf(msgValue)));
}
final List<RespTerminalSettings.ParamItem> paramList = new ArrayList<>(1);
paramList.add(new RespTerminalSettings.ParamItem(msgId, msgVal));
param.setTotalParamCount(paramList.size());
final var session = sessionManager.findByTerminalId(terminalId);
if (session.isEmpty()) {
return;
}
final int nextFlowId = session.get().nextFlowId();
final Jt808CommandKey commandKey =
Jt808CommandKey.of(terminalId, BuiltinJt808MsgType.CLIENT_COMMON_REPLY, nextFlowId);
final Object resp;
try {
resp = commandSender.sendCommandAndWaitingForReply(commandKey, param, 20L, TimeUnit.SECONDS);
log.info("RESP::::::: {}", resp);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
异常信息: nested exception is io.github.hylexus.jt.exception.JtIllegalArgumentException: java.util.List should be Iterable
异常触发位置:
基于注解的想法有了很久,最近才开始动工,但是我比较菜,正好学习一下其中的思路。
不过我的目标是可以基于注解处理一些常见规格的自定义协议而非仅限于jt808。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.