JAVA实现JT809客户端模拟数据和服务端接受数据

本文介绍了在项目中对接JT808和JT809协议时遇到的问题与解决过程。由于JT809协议资料较少,作者通过自行研究实现了JT809客户端,使用Netty3.10.6进行TCP通信,完成了登录、心跳包发送和GPS信息上报等功能。提供了客户端代码示例和优快云下载链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在项目中遇到对接JT808和JT809,其中遇到很多问题,首先因为对这两个协议不熟悉,准备在网上搜资料查询,有没有开源的关于JT808和809协议的项目,发现JT808的已经有开源的,而对于JT809的好像没有。经过两天自己查询资料,然后说下JT809,首先,不管是对接别人的数据还是接受下级的数据,都需要自己去按照官方定义的协议。先说下客户端,选择Netty3.10.6,以下是pom.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jt809client</groupId>
    <artifactId>jt809clientdemol</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.24</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.0.13</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.6</version>
        </dependency>
        <!-- endregion -->
    </dependencies>
</project>

以下是客户端的代码:

TcpClient.java

package netty.client;

import handler.Decoder;
import handler.HeartBeatHandler;
import handler.RecevieHandler;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.HashedWheelTimer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class TcpClient {

    private static final Logger LOG = LoggerFactory.getLogger(TcpClient.class);

    private static final int DEFAULT_PORT = 8001;

    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(&
以下是一个简单的C#代码示例,用于模拟JT809客户端服务端发送数据,以及服务端接收并解析数据客户端代码: ```csharp using System; using System.Net.Sockets; using System.Threading; namespace JT809Client { public class JT809Client { private TcpClient _client; private NetworkStream _stream; private Thread _thread; private bool _running; public void Connect(string host, int port) { _client = new TcpClient(); _client.Connect(host, port); _stream = _client.GetStream(); _running = true; _thread = new Thread(new ThreadStart(SendThread)); _thread.Start(); } public void Disconnect() { _running = false; _thread.Join(); _stream.Close(); _client.Close(); } private void SendThread() { var rand = new Random(); while (_running) { // 构造一个随机的消息体 byte[] body = new byte[50]; rand.NextBytes(body); // 构造一个JT809消息 var message = new JT809Message { MsgLength = (uint)(body.Length + 28), MsgSn = (uint)rand.Next(), MsgId = 0x1001, MsgBody = body }; byte[] data = JT809Serializer.Serialize(message); // 发送消息 _stream.Write(data, 0, data.Length); _stream.Flush(); // 等待一段时间 Thread.Sleep(1000); } } } public class JT809Message { public uint MsgLength { get; set; } public uint MsgSn { get; set; } public ushort MsgId { get; set; } public byte[] MsgBody { get; set; } public uint CRC32 { get; set; } public void Serialize(NetworkStream stream) { BinaryWriter writer = new BinaryWriter(stream); writer.Write(MsgLength); writer.Write(MsgSn); writer.Write(MsgId); writer.Write(MsgBody); writer.Write(CRC32); } } public class JT809Serializer { public static byte[] Serialize(JT809Message message) { MemoryStream stream = new MemoryStream(); message.Serialize(stream); byte[] data = stream.ToArray(); message.CRC32 = JT809Message.CalculateCRC32(data, 0, (uint)data.Length); stream.Seek(0, SeekOrigin.Begin); message.Serialize(stream); return stream.ToArray(); } } } ``` 服务端代码: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Threading; namespace JT809Server { public class JT809Server { private TcpListener _listener; private Thread _thread; private bool _running; public void Start(int port) { _listener = new TcpListener(IPAddress.Any, port); _listener.Start(); _running = true; _thread = new Thread(new ThreadStart(AcceptThread)); _thread.Start(); } public void Stop() { _running = false; _thread.Join(); _listener.Stop(); } private void AcceptThread() { while (_running) { TcpClient client = null; try { client = _listener.AcceptTcpClient(); var thread = new Thread(new ParameterizedThreadStart(ReceiveThread)); thread.Start(client); } catch (Exception ex) { Console.WriteLine("Error accepting client: " + ex.Message); } } } private void ReceiveThread(object obj) { var client = (TcpClient)obj; var stream = client.GetStream(); var buffer = new byte[1024]; var offset = 0; var length = 0; while (_running) { try { length = stream.Read(buffer, offset, buffer.Length - offset); if (length == 0) { break; } offset += length; if (offset < 12) { continue; } uint msgLength = BitConverter.ToUInt32(buffer, 0); if (offset < msgLength) { continue; } uint msgSn = BitConverter.ToUInt32(buffer, 4); ushort msgId = BitConverter.ToUInt16(buffer, 8); byte[] msgBody = new byte[msgLength - 12]; Array.Copy(buffer, 12, msgBody, 0, msgBody.Length); var message = new JT809Message { MsgLength = msgLength, MsgSn = msgSn, MsgId = msgId, MsgBody = msgBody }; uint crc32 = BitConverter.ToUInt32(buffer, (int)(msgLength - 4)); uint calcCrc32 = JT809Message.CalculateCRC32(buffer, 0, msgLength - 4); if (crc32 != calcCrc32) { Console.WriteLine("CRC32 check failed"); continue; } Console.WriteLine("Received message: MsgId={0}, MsgSn={1}, MsgLength={2}", msgId, msgSn, msgLength); offset -= (int)msgLength; if (offset > 0) { Array.Copy(buffer, (int)msgLength, buffer, 0, offset); } } catch (Exception ex) { Console.WriteLine("Error receiving data from client: " + ex.Message); break; } } stream.Close(); client.Close(); } } public class JT809Message { public uint MsgLength { get; set; } public uint MsgSn { get; set; } public ushort MsgId { get; set; } public byte[] MsgBody { get; set; } public uint CRC32 { get; set; } public static uint CalculateCRC32(byte[] data, uint offset, uint length) { uint[] table = new uint[] { 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, // 略... 0xF40E3585, 0xF060CF14, 0xFED41B76, 0xFA0F3D63, 0xFDBAACF8, 0xFFCCBBE1, 0xFF95C5F4, 0xFF2A7604, }; uint crc = 0xFFFFFFFF; for (uint i = offset; i < offset + length; i++) { crc = (crc << 8) ^ table[((crc >> 24) & 0xFF) ^ data[i]]; } return ~crc; } } } ``` 上述代码中,`JT809Client`类表示一个JT809客户端,用于向服务端发送随机的JT809消息。`Connect`方法用于连接到服务端,`Disconnect`方法用于断开连接。`SendThread`方法是一个线程函数,不断地构造随机的JT809消息并发送到服务端。 `JT809Server`类表示一个JT809服务端,用于接收客户端发来的JT809消息并解析。`Start`方法用于启动服务端,`Stop`方法用于停止服务端。`AcceptThread`方法是一个线程函数,不断地接受客户端连接并创建线程处理连接。`ReceiveThread`方法是一个线程函数,用于处理客户端发来的JT809消息。它首先从网络流中接收数据,然后解析出JT809消息,并验证CRC32校验码。最后输出接收到的消息的消息ID、消息序列号和消息体长度。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值