@cyysu
2017-09-06T03:17:24.000000Z
字数 5700
阅读 913
- 时间:2017年9月6日
- 作者:MJ-DZ chen yuan
- 邮箱:chenyuan@ypmingjiang.cn
- 描述:在OSGI框架的基础上,增加Mosbus协议编写,协议实现的方式由C语言实现,通过JNI来实现
- 版本:V2.0
前面简单介绍了OSGI框架搭建以及JNI如何调用底层C/C++代码,这里我们采用牛顿网关中Modbus协议进行一次小Demo演示,方便大家快速上手以及熟悉整个框架的工作过程。讲解全部在代码中用注释来表现,本文其他地方不进行讲述。如果您对本文内容有疑问或者有更好的建议和错误之处,欢迎您私信联系我。
No.1 JNI Java层
package cn.cyysu.jniInterface;/*** @ClassName: JNIinterface* @Description: TODO* @author: MJ_DZ chenyuan* @date 2017-9-5 下午02:38:52* @version V1.0*/public class JNIinterface {// 加载库中的so文件,需要指定native library路径。static{System.loadLibrary("Modbus");}// native本地方法声明public native void sendProtocol();public native byte[] recProtocol();public native void connectSocket();public native void releaseSocket();// JNI层测试,在OSGI中会将此函数注释public static void main(String[] args) {new JNIinterface().connectSocket();new JNIinterface().sendProtocol();byte[] array = new JNIinterface().recProtocol();printHex(array);new JNIinterface().releaseSocket();}// byte数组打印16进制private static void printHex(byte[] array) {System.out.println("服务器接收到的数据为:\n");for(int i = 0;i < array.length;i++)System.out.print("0x"+Integer.toHexString(+array[i] & 0xFF)+" ");System.out.println();}}
No.2 JNI JAVA层生成底层调用头文件,为自动生成
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class cn_cyysu_jniInterface_JNIinterface */#ifndef _Included_cn_cyysu_jniInterface_JNIinterface#define _Included_cn_cyysu_jniInterface_JNIinterface#ifdef __cplusplusextern "C" {#endif/** Class: cn_cyysu_jniInterface_JNIinterface* Method: sendProtocol* Signature: ()V*/JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_sendProtocol(JNIEnv *, jobject);/** Class: cn_cyysu_jniInterface_JNIinterface* Method: recProtocol* Signature: ()[B*/JNIEXPORT jbyteArray JNICALL Java_cn_cyysu_jniInterface_JNIinterface_recProtocol(JNIEnv *, jobject);/** Class: cn_cyysu_jniInterface_JNIinterface* Method: connectSocket* Signature: ()V*/JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_connectSocket(JNIEnv *, jobject);/** Class: cn_cyysu_jniInterface_JNIinterface* Method: releaseSocket* Signature: ()V*/JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_releaseSocket(JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
No.3 JNI 底层实现
#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <stdlib.h>#include <arpa/inet.h>#include "cn_cyysu_jniInterface_JNIinterface.h"#include <jni.h>// 服务器端口#define PORT 502// 数据缓冲区最大长度#define MAXDATASIZE 100// 全局变量定义int sockfd=0;char buf[MAXDATASIZE];struct sockaddr_in server;//++++++++++++++++++++++++JNI Java层函数实现++++++++++++++++++++++++++++//JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_connectSocket(JNIEnv *env, jobject object){// 1.创建socketif((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){printf("socket() error\n");exit(1);}// 2.设定服务器IP和端口bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(502);inet_pton(AF_INET,"10.0.0.47",&server.sin_addr);// 3.连接if(connect(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1){printf("connect() error\n");exit(1);}printf("socket连接成功\n");}JNIEXPORT jbyteArray JNICALL Java_cn_cyysu_jniInterface_JNIinterface_recProtocol(JNIEnv *env, jobject object){printf("服务器发送的消息内容为:");int recLength = recv(sockfd, buf, MAXDATASIZE, 0);if(recLength != -1){jbyteArray byteArr = (*env)->NewByteArray(env,recLength);(*env)->SetByteArrayRegion(env,byteArr,0,recLength,(jbyte*)buf);return byteArr;}}JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_releaseSocket(JNIEnv *env, jobject object){close(sockfd);printf("关闭socket\n");}JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_sendProtocol(JNIEnv *env, jobject object){sleep(2);char sendbuf[] = {0x00,0x06,0x00,0x00,0x00,0x06,0x01,0x03,0x00,0x00,0x00,0x0a};send(sockfd,sendbuf,sizeof(sendbuf),0);for (int i = 0; i < sizeof(sendbuf) - 1; i ++) {printf("%x ",sendbuf[i]);}printf("\n");}
No.4 动态库文件生成
// 这里给出编译正确的信息,怎么编译so文件这个在前文已经介绍过,不赘述。**** Build of configuration Debug for project Modbus ****make allBuilding file: ../src/main.cInvoking: GCC C Compilergcc -I/home/mj/桌面/arm_linux_kvm_cvm/j2sdk1.4.2/include -I"/home/mj/eclispe3.4/Modbus/src" -I/home/mj/桌面/arm_linux_kvm_cvm/j2sdk1.4.2/include/linux -O0 -g3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"src/main.d" -MT"src/main.d" -o"src/main.o" "../src/main.c"../src/main.c: In function ‘Java_cn_cyysu_jniInterface_JNIinterface_recProtocol’:../src/main.c:56:1: warning: control reaches end of non-void function [-Wreturn-type]}^Finished building: ../src/main.cBuilding target: libModbus.soInvoking: GCC C Linkergcc -shared -o"libModbus.so" ./src/main.oFinished building target: libModbus.so
No.5 OSGI框架生成
//这里需要注意的是这个包名需要和我们在JNI Java层声明的包名一致package cn.cyysu.jniInterface;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;public class Activator implements BundleActivator {/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)*/public void start(BundleContext context) throws Exception {// 载入动态库文件System.loadLibrary("Modbus");// 采用类加载机制进行调用底层代码库,这样可以保护我们上层声明代码Class cls = Class.forName("cn.cyysu.jniInterface.JNIinterface");JNIinterface jni = (JNIinterface)cls.newInstance();jni.connectSocket();jni.sendProtocol();jni.recProtocol();jni.releaseSocket();System.out.println("Hello World!!");}/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)*/public void stop(BundleContext context) throws Exception {System.out.println("Goodbye World!!");}}
No.6 元数据配置文件
Manifest-Version: 1.0Bundle-ManifestVersion: 2Bundle-Name: ModbusOSGI Plug-inBundle-SymbolicName: ModbusOSGIBundle-Version: 1.0.0Bundle-Activator: cn.cyysu.jniInterface.ActivatorBundle-Vendor: cn.cyysuBundle-NativeCode: lib/libModbus.so;osname=linux;processor=x86-64,*Bundle-RequiredExecutionEnvironment: J2SE-1.4Import-Package: org.osgi.framework;version="1.3.0"Bundle-ActivationPolicy: lazy
到此,整个Modbus OSGI 整个框架就已经完成了,下面打开Mosbus测试工具进行测试。