[关闭]
@cyysu 2017-09-06T03:17:24.000000Z 字数 5700 阅读 843

Modbus的OSGI应用篇

  • 时间:2017年9月6日
  • 作者:MJ-DZ chen yuan
  • 邮箱:chenyuan@ypmingjiang.cn
  • 描述:在OSGI框架的基础上,增加Mosbus协议编写,协议实现的方式由C语言实现,通过JNI来实现
  • 版本:V2.0

声明

  1. 前面简单介绍了OSGI框架搭建以及JNI如何调用底层C/C++代码,这里我们采用牛顿网关中Modbus协议进行一次小Demo演示,方便大家快速上手以及熟悉整个框架的工作过程。讲解全部在代码中用注释来表现,本文其他地方不进行讲述。如果您对本文内容有疑问或者有更好的建议和错误之处,欢迎您私信联系我。

项目框架

No.1 JNI Java层

  1. package cn.cyysu.jniInterface;
  2. /**
  3. * @ClassName: JNIinterface
  4. * @Description: TODO
  5. * @author: MJ_DZ chenyuan
  6. * @date 2017-9-5 下午02:38:52
  7. * @version V1.0
  8. */
  9. public class JNIinterface {
  10. // 加载库中的so文件,需要指定native library路径。
  11. static{
  12. System.loadLibrary("Modbus");
  13. }
  14. // native本地方法声明
  15. public native void sendProtocol();
  16. public native byte[] recProtocol();
  17. public native void connectSocket();
  18. public native void releaseSocket();
  19. // JNI层测试,在OSGI中会将此函数注释
  20. public static void main(String[] args) {
  21. new JNIinterface().connectSocket();
  22. new JNIinterface().sendProtocol();
  23. byte[] array = new JNIinterface().recProtocol();
  24. printHex(array);
  25. new JNIinterface().releaseSocket();
  26. }
  27. // byte数组打印16进制
  28. private static void printHex(byte[] array) {
  29. System.out.println("服务器接收到的数据为:\n");
  30. for(int i = 0;i < array.length;i++)
  31. System.out.print("0x"+Integer.toHexString(+array[i] & 0xFF)+" ");
  32. System.out.println();
  33. }
  34. }

No.2 JNI JAVA层生成底层调用头文件,为自动生成

  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class cn_cyysu_jniInterface_JNIinterface */
  4. #ifndef _Included_cn_cyysu_jniInterface_JNIinterface
  5. #define _Included_cn_cyysu_jniInterface_JNIinterface
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /*
  10. * Class: cn_cyysu_jniInterface_JNIinterface
  11. * Method: sendProtocol
  12. * Signature: ()V
  13. */
  14. JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_sendProtocol
  15. (JNIEnv *, jobject);
  16. /*
  17. * Class: cn_cyysu_jniInterface_JNIinterface
  18. * Method: recProtocol
  19. * Signature: ()[B
  20. */
  21. JNIEXPORT jbyteArray JNICALL Java_cn_cyysu_jniInterface_JNIinterface_recProtocol
  22. (JNIEnv *, jobject);
  23. /*
  24. * Class: cn_cyysu_jniInterface_JNIinterface
  25. * Method: connectSocket
  26. * Signature: ()V
  27. */
  28. JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_connectSocket
  29. (JNIEnv *, jobject);
  30. /*
  31. * Class: cn_cyysu_jniInterface_JNIinterface
  32. * Method: releaseSocket
  33. * Signature: ()V
  34. */
  35. JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_releaseSocket
  36. (JNIEnv *, jobject);
  37. #ifdef __cplusplus
  38. }
  39. #endif
  40. #endif

No.3 JNI 底层实现

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <netdb.h>
  8. #include <stdlib.h>
  9. #include <arpa/inet.h>
  10. #include "cn_cyysu_jniInterface_JNIinterface.h"
  11. #include <jni.h>
  12. // 服务器端口
  13. #define PORT 502
  14. // 数据缓冲区最大长度
  15. #define MAXDATASIZE 100
  16. // 全局变量定义
  17. int sockfd=0;
  18. char buf[MAXDATASIZE];
  19. struct sockaddr_in server;
  20. //++++++++++++++++++++++++JNI Java层函数实现++++++++++++++++++++++++++++//
  21. JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_connectSocket(JNIEnv *env, jobject object)
  22. {
  23. // 1.创建socket
  24. if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  25. {
  26. printf("socket() error\n");
  27. exit(1);
  28. }
  29. // 2.设定服务器IP和端口
  30. bzero(&server, sizeof(server));
  31. server.sin_family = AF_INET;
  32. server.sin_port = htons(502);
  33. inet_pton(AF_INET,"10.0.0.47",&server.sin_addr);
  34. // 3.连接
  35. if(connect(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1)
  36. {
  37. printf("connect() error\n");
  38. exit(1);
  39. }
  40. printf("socket连接成功\n");
  41. }
  42. JNIEXPORT jbyteArray JNICALL Java_cn_cyysu_jniInterface_JNIinterface_recProtocol(JNIEnv *env, jobject object)
  43. {
  44. printf("服务器发送的消息内容为:");
  45. int recLength = recv(sockfd, buf, MAXDATASIZE, 0);
  46. if(recLength != -1)
  47. {
  48. jbyteArray byteArr = (*env)->NewByteArray(env,recLength);
  49. (*env)->SetByteArrayRegion(env,byteArr,0,recLength,(jbyte*)buf);
  50. return byteArr;
  51. }
  52. }
  53. JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_releaseSocket(JNIEnv *env, jobject object)
  54. {
  55. close(sockfd);
  56. printf("关闭socket\n");
  57. }
  58. JNIEXPORT void JNICALL Java_cn_cyysu_jniInterface_JNIinterface_sendProtocol(JNIEnv *env, jobject object)
  59. {
  60. sleep(2);
  61. char sendbuf[] = {0x00,0x06,0x00,0x00,0x00,0x06,0x01,0x03,0x00,0x00,0x00,0x0a};
  62. send(sockfd,sendbuf,sizeof(sendbuf),0);
  63. for (int i = 0; i < sizeof(sendbuf) - 1; i ++) {
  64. printf("%x ",sendbuf[i]);
  65. }
  66. printf("\n");
  67. }

No.4 动态库文件生成

  1. // 这里给出编译正确的信息,怎么编译so文件这个在前文已经介绍过,不赘述。
  2. **** Build of configuration Debug for project Modbus ****
  3. make all
  4. Building file: ../src/main.c
  5. Invoking: GCC C Compiler
  6. 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"
  7. ../src/main.c: In function Java_cn_cyysu_jniInterface_JNIinterface_recProtocol’:
  8. ../src/main.c:56:1: warning: control reaches end of non-void function [-Wreturn-type]
  9. }
  10. ^
  11. Finished building: ../src/main.c
  12. Building target: libModbus.so
  13. Invoking: GCC C Linker
  14. gcc -shared -o"libModbus.so" ./src/main.o
  15. Finished building target: libModbus.so

No.5 OSGI框架生成

  1. //这里需要注意的是这个包名需要和我们在JNI Java层声明的包名一致
  2. package cn.cyysu.jniInterface;
  3. import org.osgi.framework.BundleActivator;
  4. import org.osgi.framework.BundleContext;
  5. public class Activator implements BundleActivator {
  6. /*
  7. * (non-Javadoc)
  8. * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
  9. */
  10. public void start(BundleContext context) throws Exception {
  11. // 载入动态库文件
  12. System.loadLibrary("Modbus");
  13. // 采用类加载机制进行调用底层代码库,这样可以保护我们上层声明代码
  14. Class cls = Class.forName("cn.cyysu.jniInterface.JNIinterface");
  15. JNIinterface jni = (JNIinterface)cls.newInstance();
  16. jni.connectSocket();
  17. jni.sendProtocol();
  18. jni.recProtocol();
  19. jni.releaseSocket();
  20. System.out.println("Hello World!!");
  21. }
  22. /*
  23. * (non-Javadoc)
  24. * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
  25. */
  26. public void stop(BundleContext context) throws Exception {
  27. System.out.println("Goodbye World!!");
  28. }
  29. }

No.6 元数据配置文件

  1. Manifest-Version: 1.0
  2. Bundle-ManifestVersion: 2
  3. Bundle-Name: ModbusOSGI Plug-in
  4. Bundle-SymbolicName: ModbusOSGI
  5. Bundle-Version: 1.0.0
  6. Bundle-Activator: cn.cyysu.jniInterface.Activator
  7. Bundle-Vendor: cn.cyysu
  8. Bundle-NativeCode: lib/libModbus.so;osname=linux;processor=x86-64,*
  9. Bundle-RequiredExecutionEnvironment: J2SE-1.4
  10. Import-Package: org.osgi.framework;version="1.3.0"
  11. Bundle-ActivationPolicy: lazy

结束语

  1. 到此,整个Modbus OSGI 整个框架就已经完成了,下面打开Mosbus测试工具进行测试。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注