java与c通信实现方案

来源:互联网 发布:js给标签添加style 编辑:程序博客网 时间:2024/06/13 10:06

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表示被注解字段的数组长度,如果该字段不是数组,则不需要使用该注解属性
原创粉丝点击