最近使用JT809协议进行数据对接,遇到了不少问题,度娘谷歌都不好使,找不到很好的客户端实现代码的例子,只能苦逼的自己闷头弄,现在特意写篇帖子,希望能帮助一些人
说正经的:
背景:跟某公司做数据对接,将本公司的一些信息推送到接收端
要求:建立tcp链接,使用接收端提供的用户名密码等信息 先登录,登录成功后推送数据,数据采用JT809标准协议
实现语言:java
下面介绍具体实现,包涵完整代码
在这之前,最好先下载jt809协议,研究研究,网上就有,我找到的里面还有一些错误别,一度让我觉得是个盗版货
首先说下整体结构:一个tcp客户端,一个Decoder,一个心跳Handler,一个处理反馈的handler,一个消息对象
通过tcp客户端链接制定ip地址和端口,进行登陆,心跳handler负责在发送数据空闲时向目标服务器发送请求保持包;decoder负责解码组装对象,反馈handler负责处理收到的反馈信息,消息对象我就不多说了
下面看代码:
TCPclient:
由于时间紧迫,代码结构有些臃肿,我使用的tcpclient为两个,一个是基类,一个子类,其实这两个可以合并到一起,这里有心的朋友自己去和,下面来看下tcpclient基类的代码,其中有一些模块的引用因为涉及到公司信息,所以我删除掉了,大家参考的时候,引用自己编写的就可以了,
//包路径,自己填
import java.net.InetSocketAddress;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.logging.LoggingHandler;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.logging.InternalLogLevel;
import org.jboss.netty.util.HashedWheelTimer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TcpClient{
private static final Logger LOG = LoggerFactory.getLogger(TcpClient.class);
private static final int DEFAULT_PORT = 9000;
private long connectTimeoutMillis = 3000;
private int port = DEFAULT_PORT;
private boolean tcpNoDelay = false;
private boolean reuseAddress = true;
private boolean keepAlive = true;
private int workerCount = 4;
private ClientBootstrap bootstrap = null;
private static Channel channel = null;
private Executor bossExecutor = Executors.newCachedThreadPool();
private Executor workerExecutor = Executors.newCachedThreadPool();
private static TcpClient instance = new TcpClient();
private TcpClient() {
init();
}
public static TcpClient getInstence(){
return instance;
}
public void init() {
bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(
bossExecutor, workerExecutor, workerCount));
bootstrap.setOption("tcpNoDelay", tcpNoDelay);
bootstrap.setOption("connectTimeoutMillis", connectTimeoutMillis);
bootstrap.setOption("reuseAddress", reuseAddress);
bootstrap.setOption("keepAlive", keepAlive);
}
public Channel getChannel(String address, int port) {
if (null == channel || !channel.isOpen()) {
bootstrap.setOption("writeBufferHighWaterMark", 64 * 1024);
bootstrap.setOption("writeBufferLowWaterMark", 32 * 1024);
bootstrap.setPipelineFactory(new ChannelPipelineFactory(){
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
// pipeline.addLast("loging", new LoggingHandler(InternalLogLevel.ERROR)); 打印日志信息,上线稳定后可去掉
pipeline.addLast("timeout", new IdleStateHandler(new HashedWheelTimer(), 10, 60, 0));//设置空闲心跳机制
pipeline.addLast("heartbeat", new HeartBeatHandler());//心跳发送包处理handler
pipeline.addLast("decode", new Decoder());//解码
pipeline.addLast("loginHandler", new RecevieHandler());//反馈数据处理
return pipeline;
}
});
ChannelFuture future = bootstrap.connect(new InetSocketAddress(
address, port));
future.awaitUninterruptibly();
if (future.isSuccess()) {
channel = future.getChannel();
} else {
throw new FrameworkRuntimeException(future.getCause());
}
}
return channel;
}
public long getConnectTimeoutMillis() {
return connectTimeoutMillis;
}
public void setConnectTimeoutMillis(long connectTimeoutMillis) {
this.connectTimeoutMillis = connectTimeoutMillis;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isTcpNoDelay() {
return tcpNoDelay;
}
public void setTcpNoDelay(boolean tcpNoDelay) {
this.tcpNoDelay = tcpNoDelay;
}
public boolean isReuseAddress() {
return reuseAddress;
}
public void setReuseAddress(boolean reuseAddress) {
this.reuseAddress = reuseAddress;
}
public boolean isKeepAlive() {
return keepAlive;
}
public void setKeepAlive(boolean keepAlive) {
this.keepAlive = keepAlive;
}
public int getWorkerCount() {
return workerCount;
}
public void setWorkerCount(int workerCount) {
this.workerCount = workerCount;
}
}
上面的配置,用过netty都不会陌生,就不多说了,下面看下子类的实现
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Cha