java与c通信实现方案

1、源代码下载

java2c

2、介绍

Java与c通信,最大的问题就是Java数据和c数据的转换问题。最近我做的项目就是java与c通过蓝牙通信,难点就是java数据结构和c结构体数据的转换问题。
通过几天的研究,实际上这个问题还是比较容易解决的,并以java自制了一个自动转换两者数据结构的工具。
Java和c两者通信都是通过流获取以及发送字节,只需要将数据结构解析成对应语言平台的字节数组,以及字节数组组装成对应语言平台的数据结构即可。

3、代码

Java工具使用方法如下

/**
 * 结构体定义
 */
public class TestBean {

//  typedef struct Books
//  {
//      char  title[10];
//      char  name;
//      int int_id[2];
//      unsigned short int short_id;
//      float book_id;
//  };
    @TXConvertData(index=0,dataType=TXDataEnum.TXChar,arrayLength=10)
    private char[] title;
    @TXConvertData(index=1,dataType=TXDataEnum.TXChar)
    private char name;
    @TXConvertData(index=2,dataType=TXDataEnum.TXInt,arrayLength=2)
    private int[] int_id;
    @TXConvertData(index=3,dataType=TXDataEnum.TXShortInt)
    private short short_id;
    @TXConvertData(index=4,dataType=TXDataEnum.TXFloat)
    private float book_id;
    public char[] getTitle() {
        return title;
    }
    public void setTitle(char[] title) {
        this.title = title;
    }
    public char getName() {
        return name;
    }
    public void setName(char name) {
        this.name = name;
    }
    public int[] getInt_id() {
        return int_id;
    }
    public void setInt_id(int[] int_id) {
        this.int_id = int_id;
    }
    public short getShort_id() {
        return short_id;
    }
    public void setShort_id(short short_id) {
        this.short_id = short_id;
    }
    public float getBook_id() {
        return book_id;
    }
    public void setBook_id(float book_id) {
        this.book_id = book_id;
    }

}
/**
 * 与c通信
 */
public class DoTest {

    public static void main(String[] args) throws Exception {
        // 创建一个数据转换工具对象
        TXDataReader<TestBean> reader = new TXDataReader<TestBean>(TestBean.class);

        SocketAddress address = new InetSocketAddress("127.0.0.1", 8888);
        Socket socket = new Socket();
        socket.connect(address);
        OutputStream out = socket.getOutputStream();
        InputStream in = socket.getInputStream();

        TestBean sendData = getBean();
        // 将java对象转为c结构体的字节数组并发送
        out.write(reader.convertToByte(sendData));
        // 获取对应c结构体的字节长度
        int len = reader.getDataLength();
        byte[] buffer = new byte[len];
        in.read(buffer);
        // 将c结构体字节数字转为java对象
        TestBean recv = reader.convertToObject(buffer);
        console(recv);
        out.close();
        socket.close();
    }

    private static TestBean getBean(){
        TestBean data = new TestBean();
        // 字符串最后一个内容后必须是0,即字符串结束符
        data.setTitle(new char[]{'h','e','l','l','o','w','o','r','l',0});
        data.setName('s');
        data.setInt_id(new int[]{123,456});
        data.setShort_id((short)32767);
        data.setBook_id(3.14f);
        return data;
    }

    private static void console(TestBean data){
        System.out.println("title:"+new String(data.getTitle()));
        System.out.println("name:"+data.getName());
        System.out.println("short_id:"+data.getShort_id());
        System.out.println("int_id[0]:"+data.getInt_id()[0]);
        System.out.println("int_id[1]:"+data.getInt_id()[1]);
        System.out.println("book_id:"+data.getBook_id());
    }
}

c代码

// TestSocketServer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>
#include <string.h>

#pragma comment(lib,"ws2_32.lib")

// 结构体定义
typedef struct Books
{
    char  title[10];
    char  name;
    //char  test;
    int int_id[2];
    unsigned short int short_id;
    float book_id;
};

int main(int argc, char* argv[])
{
    //初始化WSA
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA wsaData;
    if (WSAStartup(sockVersion, &wsaData) != 0)
    {
        return 0;
    }

    //创建套接字
    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (slisten == INVALID_SOCKET)
    {
        printf("socket error !");
        return 0;
    }

    //绑定IP和端口
    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8888);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf("bind error !");
    }

    //开始监听
    if (listen(slisten, 5) == SOCKET_ERROR)
    {
        printf("listen error !");
        return 0;
    }

    //循环接收数据
    SOCKET sClient;
    sockaddr_in remoteAddr;
    int nAddrlen = sizeof(remoteAddr);
    char revData[255];
    while (true)
    {
        printf("\n等待连接...\n");
        sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
        if (sClient == INVALID_SOCKET)
        {
            printf("accept error !");
            continue;
        }
        printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));

        //接收数据
        struct Books revBook;
        int ret = recv(sClient, revData, sizeof(Books), 0);
        if (ret > 0)
        {
            for(int i=0;i<sizeof(Books);i++){
                printf("%d,",revData[i]);
            }
            printf("\n");
            memcpy(&revBook, revData, sizeof(revBook));
            printf("title:%s\n",revBook.title);
            printf("name:%c\n",revBook.name);
            printf("short_id:%d\n",revBook.short_id);
            printf("int_id[0]:%d\n",revBook.int_id[0]);
            printf("int_id[1]:%d\n",revBook.int_id[1]);
            printf("book_id:%f\n",revBook.book_id);
        }

        struct Books book;
        strcpy_s(book.title, "hello-c1");
        book.name = 'a';
        book.int_id[0] = 253;
        book.int_id[1] = 13;
        book.book_id = 22.2;
        book.short_id = -34;

        char snd_buf[sizeof(book)];
        memset(snd_buf, 0, sizeof(book));
        memcpy(snd_buf, &book, sizeof(book));

        printf("\nlen:%d\n",sizeof(book));
        printf("\nlen:%d\n",sizeof(snd_buf));
        send(sClient, snd_buf, sizeof(snd_buf), 0);

        printf("发送:\n");
        for(int i=0;i<sizeof(snd_buf);i++){
            printf("%d,",snd_buf[i]);
        }

        closesocket(sClient);
    }

    closesocket(slisten);
    WSACleanup();
    return 0;
}

c控制台输出:
这里写图片描述
java控制台输出:
这里写图片描述

如图,成功自动将java对象转换为c结构体,以及将c结构体转换为java对象。

4、注意事项

方法com.wxtx.java2c.reflect.TXDataReader.needAlign(int, int)的作用是c结构体中的字节对齐功能。默认是按结构体中最长的字段进行字节对齐。例如例子中最长字段时float类型的book_id,所以以4字节对齐。
实际情况中c可能是其他对齐方式,根据需要可以修改该方法。

注解@TXConvertData 的使用方式:

@TXConvertData(index=0,dataType=TXDataEnum.TXChar,arrayLength=10)
private char[] title;
  1. index表示被注解的字段在c结构体中的序号(从0开始计数);
  2. dataType表示被注解字段的数据类型,分别有TXDataEnum.TXInt,TXDataEnum.TXShortInt,TXDataEnum.TXChar,TXDataEnum.TXFloat。因为这次项目中涉及到的数据类型就这4种,所以也就没有什么动力在添加double以及其他的数据类型。至于结构体中嵌套结构体的情况,只需要进行递归解析即可,有需求的小伙伴自行修改工具代码吧,哈哈哈;
  3. arrayLength表示被注解字段的数组长度,如果该字段不是数组,则不需要使用该注解属性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值