@cyysu
2017-09-06T03:17:24.000000Z
字数 5700
阅读 843
- 时间: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 __cplusplus
extern "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.创建socket
if((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 all
Building file: ../src/main.c
Invoking: GCC C Compiler
gcc -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.c
Building target: libModbus.so
Invoking: GCC C Linker
gcc -shared -o"libModbus.so" ./src/main.o
Finished 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.0
Bundle-ManifestVersion: 2
Bundle-Name: ModbusOSGI Plug-in
Bundle-SymbolicName: ModbusOSGI
Bundle-Version: 1.0.0
Bundle-Activator: cn.cyysu.jniInterface.Activator
Bundle-Vendor: cn.cyysu
Bundle-NativeCode: lib/libModbus.so;osname=linux;processor=x86-64,*
Bundle-RequiredExecutionEnvironment: J2SE-1.4
Import-Package: org.osgi.framework;version="1.3.0"
Bundle-ActivationPolicy: lazy
到此,整个Modbus OSGI 整个框架就已经完成了,下面打开Mosbus测试工具进行测试。