移植UDT到Android平台

UDT是UDP Based Data Transfer的缩写,这是一个基于UDP协议的在应用层实现的一种面向连接的传输协议,主要目的是在于支持高速广域网上的数据海量传输。其采用C++开发,具有高度的可移植性,并且开源,你可以在这里下载到UDT的源码https://sourceforge.net/projects/udt/

在开发者提供的代码中,包含了UDT的核心代码和应用例程,并提供了Visual Studio的Windows项目工程和Linux下的Makefile。这里我们将要参考Linux下的makefile并使用Android NDK在Windows下将其移植到Android平台。

移植步骤:

1.创建一个jni目录,这里我们使用F:\UDT\jni

2.把下载得到的udt源码放到jni目录里,这里就变成了F:\UDT\jni\udt4

3.创建Android.mk文件,内容为

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

APP_STL := gnustl_static

LOCAL_CFLAGS := -DLINUX -fvisibility=hidden

LOCAL_CPP_FEATURES += exceptions

LOCAL_ARM_MODE := arm

LOCAL_CPPFLAGS := -fPIC -Wall -Wextra -DLINUX -finline-functions -O3 -fno-strict-aliasing -fvisibility=hidden

LOCAL_LDLIBS :=-L$(SYSROOT)/usr/lib -llog

LOCAL_C_INCLUDES := /usr/include/c++/4.5/

LOCAL_CPP_EXTENSION:=.cpp

LOCAL_MODULE := udt

LOCAL_SRC_FILES := md5.cpp common.cpp window.cpp list.cpp buffer.cpp packet.cpp channel.cpp queue.cpp ccc.cpp cache.cpp core.cpp epoll.cpp api.cpp

include $(BUILD_SHARED_LIBRARY)

并把其放到src目录下

4.分别在jni和udt4目录下创建Android.mk,内容为

include $(all-subdir-makefiles)

APP_CPPFLAGS += -fexceptions

同时在jni目录下创建Application.mk,内容为

APP_STL := gnustl_static

5.在jni目录下使用ndk-build命令,我们可以发现在F:\UDT目录下生成了libs和obj目录,其中libs中有我们可以在Android中使用到的so库。

下面将介绍如何在程序中使用UDT,以移植UDT例程recvfile为例。

因为UDT的库中并没有适用于Android的接口函数,所以我们需要再写一个能够在JNI中调用的库来构建UDT库和Android应用程序之间的桥梁。

因为本人还没有了解新版本Android Studio中cmake的使用方法,所以我们将以传统NDK-build方式来实现。

  1. 我们新建一个名为UDTRecv的Android Studio项目。
  2. 在app\src\main下新建jni目录,在jni目录下建立include和lib目录。
  3. 把我们之前得到的so放到lib目录中。把udt4的src目录中所有的.h头文件放到include目录中。把udt4的src目录中的recvfile.cpp拷贝到jni目录。目录结构如下:

  1. 编辑cpp使其支持JNI

具体如下:

添加jni头文件引用

#include <jni.h>

更改主函数main()为JNI支持的函数名称

JNIEXPORT jint JNICALL Java_net_meoi_udtrecv_MainActivity_RecvFileFromServer(
JNIEnv* env, jclass cls,jstring UDTServerAddress,jstring UDTServerPortStr,jstring RemoteFileName,jstring LocalFileName)

更改内部变量调用使其能够正常工作。

  1. 在jni目录下创建Android.mk,内容为
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE:= udt

LOCAL_SRC_FILES:= lib/libudt.so

LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/include

include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_CPP_EXTENSION:=.cpp

include $(CLEAR_VARS)

PATH_TO_UDT_SOURCE:=./include/

PATH_TO_LIBUDT_SO:=./lib/

LOCAL_C_INCLUDES += $(PATH_TO_UDT_SOURCE)

LOCAL_LDLIBS := -llog

LOCAL_SHARED_LIBRARIES := udt

LOCAL_MODULE := recvfile

LOCAL_SRC_FILES := recvfile.cpp
include $(BUILD_SHARED_LIBRARY)

和Application.mk,内容为

APP_STL := gnustl_static

APP_ABI := armeabi-v7a

APP_PLATFORM := android-21
  1. 在jni目录中执行ndk-build,在上一级目录中将生成lib目录,我们把它更名为jniLibs,里面包含了armeabi-v7a平台下的两个库文件,一个是udt核心库,一个是recvfile例程的库。至此我们c语言部分的代码已经移植完毕,接下来编写Android Java部分
  2. 编写主程序,同时注意需要声明JNI函数
private native static int RecvFileFromServer(String UDTServerAddress,String UDTServerPortStr,String RemoteFileName,String LocalFileName);

并且调用两个刚刚生成的库文件。

static {
System.loadLibrary("udt");
System.loadLibrary("udtrecvfile");
}
  1. 在工程目录下的properties文件的末尾加上一句:
    Android.useDeprecatedNdk=true
  2. 在文件gradle(Module:app)里面的buildTypes类中添加一个这样的方法
sourceSets {

main {

jni.srcDirs = []

}
}
  1. 编译,运行,测试

这是一个写好的demo: https://github.com/MeoRean/UDTRecv

这是我第一次用github,如有问题请多多指教,谢谢

参考资料:

https://www.cnblogs.com/uvsjoh/archive/2013/03/28/2987302.html

https://blog.csdn.net/chenxupro/article/details/8801761

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据