Java和C++通过Socket传递结构体

Java和C++通过Socket传递结构体

前言

  1. 上一篇 Android端 - 通过Socket以及TCP协议和MFC端通信(Receive篇) 中写到 Android端和PC端通过Socket在局域网条件下传输信息即文件;
  2. 本文将实现 Java 端和 PC 端通过 Socket 传递结构体;

PC 端

  1. 结构体如下:

    //SendMD5andLogDlg.h : 头文件中
    typedef struct  
    {
    	int nMsgCode;
    	double pdDataX[2];
    	double pdDataY[2];
    	int nDataCnt;
    }ST_MSG;
    
  2. 取消 C++ 自动的字节对齐:

    //SendMD5andLogDlg.h : 头文件中
    #pragma once
    #pragma pack(push,1) //主要添加这一句!
    
    ……
    
    #pragma(pop)//末尾一天给添加这一句
    

PC 端注意

  1. 结构体是个好东西 (可惜我不会) ;
  2. C++ 发送和接受的结构体 实际上是字节流 byte[];所以要注意在 Java 端将 对象转换成字节流发送;将字节流解析成对象;
  3. C++ 结构体定义的参数顺序至关重要,传递、解析都要按照该顺序;
  4. C++ 存在自 (xian)(de)(dan)(teng);举个栗子:我这里的结构体参数为 int double double …… double int ;众所周知,int 4 个字节,double 8个字节(注意:Java和C++中这两个基本类型所占的字节数是一致的!如果你是使用其他类型,记得字节转换问题!)在Java中不存在字节对齐,所以字节数就是 4+ 8 + 8 +…… + 8 + 4 ;但是C()+() 给自动对齐了结果是: 8 + 8 + 8 +……+ 8 + 8;取消蛋疼的字节对齐已经在上面写了;下面我将用 蛋疼 代替 *语言

Android端

  1. 创建对应的类;并给出对应参数;构造器;

    public class PcStruct {
    
    	public byte[] buf;
    	
    	public int nMsgCode;
        public int nDataCnt;
        public double pdDataX[] = new double[2];
        public double pdDataY[] = new double[2];
        
        public int getnMsgCode() {
            return nMsgCode;
        }
    
        public void setnMsgCode(int nMsgCode) {
            this.nMsgCode = nMsgCode;
        }
    
        public int getnDataCnt() {
            return nDataCnt;
        }
    
        public void setnDataCnt(int nDataCnt) {
            this.nDataCnt = nDataCnt;
        }
    
        public double[] getPdDataX() {
            return pdDataX;
        }
    
        public void setPdDataX(double[] pdDataX) {
            this.pdDataX = pdDataX;
        }
    
        public double[] getPdDataY() {
            return pdDataY;
        }
    
        public void setPdDataY(double[] pdDataY) {
            this.pdDataY = pdDataY;
        }
    
        public static final String TAG = PcStruct.class.getClass().getSimpleName();
    
    
        public PcStruct(byte[] buf) {
            this.buf = buf;
        }
        ……
    
  2. 提供解析字节流的构造器;

    /**
     * 通过接收到的 byte[] 对象解析成结构体对象;由于PC还没有进行字节对齐,故得到的自己数为48个;int由4个字节 被蛋疼对齐成8个字节;
     * @param bytes 来自 PC 端的字节流文件;
     * @return 返回一个对象;
     */
    public static PcStruct getPcStructInstance(byte[] bytes) {
        PcStruct pcStruct = new PcStruct();
        byte[] tempBytes4 = new byte[8];
        byte[] tempBytes8 = new byte[8];
        System.arraycopy(bytes, 0, tempBytes4, 0, 8);
        pcStruct.setnMsgCode(byteArrayToInt(tempBytes4));
        System.arraycopy(bytes, 40, tempBytes4, 0, 8);
        pcStruct.setnDataCnt(byteArrayToInt(tempBytes4));
        System.arraycopy(bytes, 8, tempBytes8, 0, 8);
        double mPdDataX0 = byteArrayToDouble(tempBytes8);
        System.arraycopy(bytes, 16, tempBytes8, 0, 8);
        double mPdDataX1 = byteArrayToDouble(tempBytes8);
        double[] mPdDataX = new double[]{mPdDataX0, mPdDataX1};
        pcStruct.setPdDataX(mPdDataX);
        System.arraycopy(bytes, 24, tempBytes8, 0, 8);
        double mPdDataY0 = byteArrayToDouble(tempBytes8);
        System.arraycopy(bytes, 32, tempBytes8, 0, 8);
        double mPdDataY1 = byteArrayToDouble(tempBytes8);
        double[] mPdDataY = new double[]{mPdDataY0, mPdDataY1};
        pcStruct.setPdDataY(mPdDataY);
        return pcStruct;
    }
    
  3. 提供将对象转换成字节流的途径:如下:

    /**
     * 这里通过构造器 + getBuf() 的方式,获取输出字节流,向PC端传输结构体;
     * 这里 PC 端已经设置为原始对齐方式,即,字节 无 对齐方式;这里需要注意的是!传递的顺序 应该和PC端定义结构参数的顺序一致
     */
    //参数字节:4+4 + 8+8+8+8
    public PcStruct(int nMsgCode, int nDataCnt, double pdDataX0, double pdDataX1, double pdDataY0, double pdDataY1) {
        byte[] tempByte4 = new byte[4];
        byte[] tempByte8 = new byte[8];
        buf = new byte[40];
        tempByte4 = toLH(nMsgCode);
        System.arraycopy(tempByte4, 0, buf, 0, 4);
        tempByte8 = toLH(pdDataX0);
        System.arraycopy(tempByte8, 0, buf, 4, 8);
        tempByte8 = toLH(pdDataX1);
        System.arraycopy(tempByte8, 0, buf, 12, 8);
        tempByte8 = toLH(pdDataY0);
        System.arraycopy(tempByte8, 0, buf, 20, 8);
        tempByte8 = toLH(pdDataY1);
        System.arraycopy(tempByte8, 0, buf, 28, 8);
        tempByte4 = toLH(nDataCnt);
        System.arraycopy(tempByte4, 0, buf, 36, 4);
    }
    /**
     * 返回要发送的数组
     */
    public byte[] getBuf() {
        return buf;
    }
    
  4. 提供以下字节转换的方法:这里只提供我用过好用的 int 和 double 类型;

    /**
     * 将int转为低字节在前,高字节在后的byte数组
     */
    private static byte[] toLH(int n) {
        byte[] b = new byte[4];
        b[0] = (byte) (n & 0xff);
        b[1] = (byte) (n >> 8 & 0xff);
        b[2] = (byte) (n >> 16 & 0xff);
        b[3] = (byte) (n >> 24 & 0xff);
        return b;
    }
    /**
     * double 转 byte[] 小端 低前高后
     */
    public static byte[] toLH(double data) {
        long intBits = Double.doubleToLongBits(data);
        byte[] bytes = getLongBytes(intBits);
        return bytes;
    }
    /**
     * 好使!字节数组到int的转换.
     */
    public static int byteArrayToInt(byte[] b) {
        int s = 0;
        // 最低位
        int s0 = b[0] & 0xff;
        int s1 = b[1] & 0xff;
        int s2 = b[2] & 0xff;
        int s3 = b[3] & 0xff;
        s3 <<= 24;
        s2 <<= 16;
        s1 <<= 8;
        s = s0 | s1 | s2 | s3;
        return s;
    }
    /**
     * 好使!字节数组到double的转换.
     */
    public static double byteArrayToDouble(byte[] b) {
        long m;
        m = b[0];
        m &= 0xff;
        m |= ((long) b[1] << 8);
        m &= 0xffff;
        m |= ((long) b[2] << 16);
        m &= 0xffffff;
        m |= ((long) b[3] << 24);
        m &= 0xffffffffl;
        m |= ((long) b[4] << 32);
        m &= 0xffffffffffl;
        m |= ((long) b[5] << 40);
        m &= 0xffffffffffffl;
        m |= ((long) b[6] << 48);
        m &= 0xffffffffffffffl;
        m |= ((long) b[7] << 56);
        return Double.longBitsToDouble(m);
    }
    
  5. 当然这是简单的数据,实际上,我们的数据上千个,这种方法显然是不靠谱的,我最近看到 JNA 模拟结构体可以轻松实现以上办法,之后应该会使用这种方法,请关注我吧!我会及时更新的!


感谢

  1. 我虽是学习 Java、Android,但难免存在知识盲点,比如 网络编程;以及 Java 和 C++ 的区别之类;

  2. 本文参考自以下文章,但应该不止以下文章,向他们表示感谢!

    参考:https://blog.csdn.net/qq_40384776/article/details/103711300
    https://blog.csdn.net/lianxianxun230/article/details/77428669
    https://www.cnblogs.com/linzhanfly/p/9794752.html
    https://blog.csdn.net/DoasIsay/article/details/103797033

    基本类型转 byte 数组:https://www.cnblogs.com/moonciki/p/8145834.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liusaisaiV1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值