java-如何在tcp端口上使用二进制通信协议发送数据包

java-如何在tcp端口上使用二进制通信协议发送数据包,第1张

概述我正在开发一种可以通过传感器测量一些读数的设备.设备由Android应用 *** 作.我必须从TCP层读取数据.这是在TCP上发送数据的代码TcpClient.javaimportandroid.util.Log;importjava.io.BufferedReader;importjava.io.BufferedWriter;importjava.io.InputStreamReader;impor

我正在开发一种可以通过传感器测量一些读数的设备.设备由Android应用 *** 作.我必须从TCP层读取数据.这是在TCP上发送数据的代码

TcpClIEnt.java

import androID.util.Log;import java.io.BufferedReader;import java.io.BuffereDWriter;import java.io.inputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.InetAddress;import java.net.socket;/*** Created by shahbaz on 25/4/17.*/ public class TcpClIEnt { public static final String SERVER_IP = "192.168.1.76"; //server IP address public static final int SERVER_PORT = 1800; // message to send to the server private String mServerMessage; // sends message received notifications private OnMessageReceived mMessageListener = null; // while this is true, the server will continue running private boolean mRun = false; // used to send messages private PrintWriter mBufferOut; // used to read messages from the server private BufferedReader mBufferIn; /**  * Constructor of the class. OnMessagedReceived Listens for the messages received from server  */ public TcpClIEnt(OnMessageReceived Listener) {    mMessageListener = Listener; }/** * Sends the message entered by clIEnt to the server * * @param message text entered by clIEnt */public voID sendMessage(String message) {    if (mBufferOut != null && !mBufferOut.checkerror()) {        mBufferOut.println(message);        mBufferOut.flush();    }}/** * Close the connection and release the members */public voID stopClIEnt() {    mRun = false;    if (mBufferOut != null) {        mBufferOut.flush();        mBufferOut.close();    }    mMessageListener = null;    mBufferIn = null;    mBufferOut = null;    mServerMessage = null;}public voID run() {    mRun = true;    try {        //here you must put your computer's IP address.        InetAddress serverAddr = InetAddress.getByname(SERVER_IP);        Log.e("TCP ClIEnt", "C: Connecting...");        //create a socket to make the connection with the server        Socket socket = new Socket(serverAddr, SERVER_PORT);        try {            //sends the message to the server            mBufferOut = new PrintWriter(new BuffereDWriter(new OutputStreamWriter(socket.getoutputStream())), true);            //receives the message which the server sends back            mBufferIn = new BufferedReader(new inputStreamReader(socket.getinputStream()));            //in this while the clIEnt Listens for the messages sent by the server            while (mRun) {                mServerMessage = mBufferIn.readline();                if (mServerMessage != null && mMessageListener != null) {                    //call the method messageReceived from MyActivity class                    mMessageListener.messageReceived(mServerMessage);                }            }            Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'");        } catch (Exception e) {            Log.e("TCP", "S: Error", e);        } finally {            //the socket must be closed. It is not possible to reconnect to this socket            // after it is closed, which means a new socket instance has to be created.            socket.close();        }    } catch (Exception e) {        Log.e("TCP", "C: Error", e);    }}   //Declare the interface. The method messageReceived(String message) will must be implemented in the MyActivity   //class at on asynckTask doInBackground   public interface OnMessageReceived {    public voID messageReceived(String message);}

}

数据包结构

包格式包含
在TCP上与设备通信时,无法识别数据包之间的边界,在这种情况下,如果数据包顺序不正确或丢失了任何数据包,则可以使用“头开始”来识别新数据包.
因此,数据包中的前2个字节代表数据包的开始.

标头开始:两字节字段,指示每个数据包的开始. 0x55AA是2个字节的数字,用作标头开始.

协议版本:一字节字段,用于指定所使用协议的版本.有效负载中指定的版本将决定有效负载的结构.在任何给定的时刻,设备将支持单个协议版本.当前协议版本为“ 1”.

DSN:序列号是1个字节的字段,它将唯一地标识数据包.数据包的请求者将不得不在请求有效负载中填充此字段;响应者必须在响应有效负载中填充相同的唯一标识符.

请求ID:一字节字段指定命令ID.有效载荷的解析将基于命令ID进行.在请求有效负载的情况下,该字段将为非零;在响应的情况下,该字段将为零.

有效负载长度:两字节字段指定有效负载的长度(以字节为单位).它指定有效负载长度字段后面的字节数.在有效载荷长度中,不包括报头长度和CRC.当前,网关设备支持的最大有效负载长度为512(字节).
CRC:1个字节的字段,将通过对所有字节进行XOR运算并加上XOR计数0来计算.

它正在工作.但是根据文档,我必须使用二进制通信协议发送数据包.包括标头开始,有效载荷数据等.如何以包结构发送这些参数?如何创建数据包?

任何帮助表示赞赏.

解决方法:

主要的错误是我没有考虑太多原始数据类型的大小.

位元组= 1个位元组

短= 2字节

int = 4个字节

长= 8字节

浮点数= 4字节

双倍= 8字节

字符= 2字节

引用原始数据类型的大小后,我意识到我们应该跟踪数据包的大小和索引,因为我们正在处理字节数组.

TcpPacket.java

public class TcpPacket {private static int header_start =  0x55AA;private static int protocol_version = 1;private PacketUtils packetUtils = new PacketUtils(); public byte[] getHandshakePacket() {    int request_ID = 1;    byte[] header_data = packetUtils.ItoBA2(header_start);    byte[] payload_data = packetUtils.ItoBA4(packetUtils.getDateTime());    byte[] payload_length = packetUtils.ItoBA2(4);    byte[] a_data = new byte[]{header_data[0], header_data[1], (byte) protocol_version, packetUtils.getDSN(), (byte) request_ID, payload_length[0], payload_length[1],            payload_data[0], payload_data[1], payload_data[2], payload_data[3]};    byte[] b_data = new byte[]{ packetUtils.getCRC(a_data)};    byte[] packet_data = packetUtils.concatBytes(a_data,b_data);    return packet_data; }}

PacketUtils.java

public class PacketUtils {public byte[] ItoBA4(int value) {       // integer to bytes function (return byte array of 4 bytes)    return new byte[] {            (byte)(value >>> 24),            (byte)(value >>> 16),            (byte)(value >>> 8),            (byte)value};}public byte[] ItoBA2(int value) {   // integer to bytes function (return byte array of 2 bytes)    return new byte[] {            (byte)(value >>> 8),            (byte)value};}public byte getDSN()    // return one byte random number{    char[] chars = "1234567890".tochararray();    StringBuilder sb = new StringBuilder();    Random random = new Random();    for (int i = 0; i < 1; i++) {        char c = chars[random.nextInt(chars.length)];        sb.append(c);    }    byte output = Byte.valueOf(sb.toString());    return output;}public byte getCRC(byte[] packet)   //  required CRC function (return byte){    try    {        if (packet == null)        {            //Logger.Error("empty packet received");            return (byte)0;        }        byte XORCheckSum = 0;        byte zeroCount = 0;        byte FFCount = 0;        for (int i = 0; i < packet.length; i++)        {            XORCheckSum ^= packet[i];            if (packet[i] == (byte) 0)            {                zeroCount++;                continue;            }            if (packet[i] == (byte)255)            {                FFCount++;                continue;            }        }        XORCheckSum ^= zeroCount;        XORCheckSum ^= FFCount;        return XORCheckSum;    }    catch (Exception ex)    {        //Logger.Error(ex);        return (byte)0;    }}byte[] concatBytes(byte[]...arrays)     //  concatenate byte arrays{    // Determine the length of the result array    int totalLength = 0;    for (int i = 0; i < arrays.length; i++)    {        totalLength += arrays[i].length;    }    // create the result array    byte[] result = new byte[totalLength];    // copy the source arrays into the result array    int currentIndex = 0;    for (int i = 0; i < arrays.length; i++)    {        System.arraycopy(arrays[i], 0, result, currentIndex, arrays[i].length);        currentIndex += arrays[i].length;    }    return result;}public int getDateTime(){    int dateInSec = (int) (System.currentTimeMillis() / 1000);    return dateInSec;}}
总结

以上是内存溢出为你收集整理的java-如何在tcp端口上使用二进制通信协议发送数据包全部内容,希望文章能够帮你解决java-如何在tcp端口上使用二进制通信协议发送数据包所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1121033.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-29
下一篇 2022-05-29

发表评论

登录后才能评论

评论列表(0条)

保存