java - 如何使用java套接字编程解码C结构(如数据包)

标签 java sockets

java 套接字编程新手!我正在尽力理解java套接字编程,以及如何解码像数据包一样的“C”strut。

客户端是python,它在标签之间发送数据包, 示例有效负载:<tag1> data packet 1</tag1><tag2>data packet 2</tag2>

有一个c代码来接收有效负载并用结构解码有效负载,所有标签都是30字节,数据包1,2,..n将具有不同的结构

我对java程序相当陌生,在通过网络搜索后,我可以编写一个从客户端接收有效负载的套接字服务器,现在面临解码数据包的问题。 我可以显示字节。所以使用Arrays.copyOfRange方法来获取数据。

数据包数据如下所示,

typedef struct {

  unsigned char     dataType;
  unsigned char     value[4];

} GEN_VAL

typedef struct {

  unsigned char     dataType;
  unsigned char     numBytes;
  unsigned char     value[32];

} GEN_STR_32;

typedef struct {

    char           startTag[32];
    GEN_STR_32     c_code;
    GEN_STR_32     c_name;
    GEN_STR_32     c_info;

    GEN_VAL        i_type;
    GEN_VAL        i_count1;
    GEN_VAL        i_count2;
    char           endTag[32];

} DATA_PACKET_1;

我收到带有以下代码片段的缓冲区

  DataInputStream inStream = new DataInputStream
                        (new BufferedInputStream(socket.getInputStream()));

 while ( ( noOfBytes = (int)inStream.read(recvBuff)) != -1)
{
 cDecode mydecode = new cDecode();
 mydecode.decodePacket(noOfBytes, recvBuff);
}

cDecode.java

public void decodePacket(int TotalBytes, byte[] BuffRecv) 
{
    byte[] GetTag = new byte[32];
    byte[] GEN_STR_32 = new byte[32];
    byte[] GEN_INT_4  = new byte[4];

     GetTag = Arrays.copyOfRange(BuffRecv,0,31);
     String TagStr = new String(GetTag).trim();  //get start tag 

     int startloc = 31;
     int offset = startloc + 32;
     GEN_STR_32 = Arrays.copyOfRange(Buff,startloc,offset);
     String cCode = new String(GEN_STR_32).trim();  // get value of cCode
     System.out.println("Code   :" + cCode );

     startloc = offset;
     offset = startloc + 32;
     GEN_STR_32 = Arrays.copyOfRange(Buff,startloc,offset);
     String cName = new String(GEN_STR_32).trim(); //get value of cName
     System.out.println("Name:" + cName );

     startloc = offset;
     offset = startloc + 32;
     GEN_STR_32 = Arrays.copyOfRange(Buff,startloc,offset);
     String cInfo = new String(GEN_STR_32).trim(); //get value of cName
     System.out.println("Info:" + cInfo );

     startloc = offset;
     offset = offset + 4;
     ByteBuffer iTypeByteBuff = ByteBuffer.wrap(GEN_DATA_INT_4);
     int iType= iTypeByteBuff .getInt();
     System.out.println("type :" + iType);

     startloc = offset;
     offset = offset + 4;
     // likewise used ByteBuffer for remaining integer data 
     // for receiving end tag, offset is added with 32!
}

前 3 个数据是字符串值并且
第二个 3 数据具有整数值

字符串值显示正确。
在将字节转换为整数时发现问题,不确定我是否在 Arrays.copyOfRange 方法中使用正确的 startloc 和 offset 值。

我根据从网上得到的信息尝试了这个。

我还了解到有一个单独的类,没有适用于所有数据结构的方法。但我找不到任何完整的例子,因为“sizeof”在java中不可用。

有人可以指导我在这种情况下解码数据包的正确方法吗?

最佳答案

对于字节数组或输入/输出,您可以使用 ByteBuffer。

byte[] bytes = ...
ByteBuffer buf = ByteBuffer.wrap(bytes);
buf.order(ByteOrder.LITTLE_ENDIAN); // Intel byte order.
short sh = buf.getShort(sh); // Java short = 2B
int unsignedSh = buf.getShort() & 0xFFFF; // Unsigned short emulation


ByteBuffer buf = ByteBuffer.allocate(4);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.putShort(sh); // Java short = 2B
buf.putShort((short) unsignedSh);

还有一个二进制格式标准ASN,可以像更多语法一样工作,但在这种情况下,上面的就可以了。

C端的一个问题是领域对齐和平台可移植性。人们可以使用宏将结构转换为完全指定的二进制数据结构构建调用。

<小时/>

评论后,使用 DataInputStream

您似乎没有使用 DataInputStream 的数据特定读取调用。

enum DataType {
    X0,
    GEN_VAL,
    X2,
    X3,
    GEN_STR_32,
    ...
}

class GenStr32 {
     final DataType dataType = DataType.GEN_STR_32;
     int numbytes; // 0..255
     String value; // 32 bytes incl. '\0' in C
}

void readAnyTyped(DataInputStream in) {
    int dataTypeIx = in.readByte() & 0xFF;
    DataType dataType = DataType.values()[dataTypeIx];
    switch (dataType) {
    case GEN_STR_32:
        GenStr32 data = new GenStr32();
        data.numbytes = in.readByte();
        byte[] bytes = new byte[data.numbytes]; // or 32?
        bytes = in.readFully();
        int length = 0;
        while (length < bytes.length && bytes[length] != 0) {
            ++length;
        }
        data.value = new String(bytes, 0, length,
            StandardCharsets.ISO_8859_1);
        process(data);
        break;
    }
}

DataInputStream 可能更直接。 ByteBuffer 的优点是可指定字节顺序,因为 java 默认为 BIG_ENDIAN。

关于java - 如何使用java套接字编程解码C结构(如数据包),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31317196/

相关文章:

java - 修复 java.net.SocketTimeoutException : Read timed out

java - 针对远程 Wildfly-8.0.0 运行 arquillian 时出现 NPE

c - sendto 函数出错

Java 套接字 : how to prevent java.net.BindException

sockets - Socket到底是什么

java - 为什么我收到 IOException : PDF header signature not found when creating a PDF?

java - 如何在 Net-Beans(或一般 Java)中设置 FileReader 的路径?

java覆盖不工作

c - 嵌入式设备上的 Unix 域套接字代码失败

java - Socket 的 getOutputStream() 是如何工作的?