简体   繁体   English

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

[英]How to send packet using binary communication protocol on tcp port

I am working on a device which would work to measure some readings through sensors. 我正在研究一种可以通过传感器测量一些读数的设备。 Device is operated by an Android app. 设备由Android应用程序运营。 I have to take readings from TCP layer. 我必须从TCP层获取读数。 This is the code to send data on TCP 这是在TCP上发送数据的代码

TcpClient.java 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);
}

} }

包格式 Packet Structure 数据包结构

Packet format contains, While communicating with the device on TCP, boundaries between packets are not identified, in this case if the packets are out of sequence or if any of the packets is missed one can identify a new packet using 'header start'. 数据包格式包含,当在TCP上与设备通信时,不识别数据包之间的边界,在这种情况下,如果数据包无序或者如果丢失了任何数据包,则可以使用“报头启动”识别新数据包。 So, first 2 bytes in the packet represent the start of the packet. 因此,数据包中的前2个字节表示数据包的开始。

Header start: Two-byte field that indicates the start of every packet. 标头开始:双字节字段,指示每个数据包的开始。 0x55AA is a 2 bytes number used as header start. 0x55AA是用作头开始的2字节数。

Protocol version: One-byte field to specify the version of the protocol in use. 协议版本:单字节字段,用于指定正在使用的协议版本。 Version specified in the payload will decide the payload structure. 有效载荷中指定的版本将决定有效载荷结构。 At any given moment a device will support single protocol version. 在任何给定时刻,设备将支持单协议版本。 Present protocol version is '1'. 目前的协议版本为'1'。

DSN: Sequence number is 1-byte field which will identify the packet uniquely. DSN:序列号是1字节字段,它将唯一地标识数据包。 Requester of the packet will have to fill this field in request payload; 数据包的请求者必须在请求有效载荷中填写此字段; responder has to fill the same unique identifier in the response payload. 响应者必须在响应有效负载中填充相同的唯一标识符。

Request Id: One-byte field specifies the command id. 请求ID:单字节字段指定命令ID。 The parsing of the payload will be done on the basis of the command id. 有效载荷的解析将基于命令id完成。 In case of request payload this field will be non zero and in case of response it will be zero. 在请求有效载荷的情况下,该字段将不为零,并且在响应的情况下它将为零。

Payload length: Two-byte field specifies the length of the payload in bytes. 有效载荷长度:双字节字段以字节为单位指定有效载荷的长度。 It specifies the number of bytes followed payload length field. 它指定了有效负载长度字段的字节数。 In the payload length, header length and CRC is not included. 在有效载荷长度中,不包括报头长度和CRC。 Currently, Max payload length supported by gateway device is 512 (bytes). 目前,网关设备支持的最大有效载荷长度为512(字节)。 CRC: 1 byte field which will be calculated by XORing all the bytes and add the XOR count of 0. CRC:1字节字段,通过对所有字节进行异或运算并将XOR计数加0来计算。

And it is working. 它正在发挥作用。 But according to docs I have to send packet using binary communication protocol. 但根据文档我必须使用二进制通信协议发送数据包。 Including header start , payload data , etc. How can I send these params in packet structure? 包括头开始有效载荷数据等。如何在数据包结构中发送这些参数? How can I create packet? 我该如何创建数据包?

Any help is appreciated. 任何帮助表示赞赏。

The main mistake was that I was not thinking much about size of primitive data types. 主要的错误是我没有考虑原始数据类型的大小。

byte = 1 byte byte = 1个字节

short = 2 bytes short = 2个字节

int = 4 bytes int = 4个字节

long = 8 bytes long = 8个字节

float = 4 bytes float = 4个字节

double = 8 bytes double = 8个字节

char = 2 byte char = 2个字节

After referencing the size of primitive datatypes I realised we should track the size and index of packet because we are dealing with byte array. 在引用原始数据类型的大小后,我意识到我们应该跟踪数据包的大小和索引,因为我们正在处理字节数组。

TcpPacket.java 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 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;

}



}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM