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方式来实现。
我们新建一个名为UDTRecv的Android Studio项目。
在app\src\main下新建jni目录,在jni目录下建立include和lib目录。
把我们之前得到的so放到lib目录中。把udt4的src目录中所有的.h头文件放到include目录中。把udt4的src目录中的recvfile.cpp拷贝到jni目录。目录结构如下:
编辑cpp使其支持JNI
具体如下:
添加jni头文件引用
#include
更改主函数main()为JNI支持的函数名称
JNIEXPORT jint JNICALL Java_net_meoi_udtrecv_MainActivity_RecvFileFromServer(
JNIEnv* env, jclass cls,jstring UDTServerAddress,jstring UDTServerPortStr,jstring RemoteFileName,jstring LocalFileName)
更改内部变量调用使其能够正常工作。
在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
在jni目录中执行ndk-build,在上一级目录中将生成lib目录,我们把它更名为jniLibs,里面包含了armeabi-v7a平台下的两个库文件,一个是udt核心库,一个是recvfile例程的库。至此我们c语言部分的代码已经移植完毕,接下来编写Android Java部分
编写主程序,同时注意需要声明JNI函数
private native static int RecvFileFromServer(String UDTServerAddress,String UDTServerPortStr,String RemoteFileName,String LocalFileName);
并且调用两个刚刚生成的库文件。
static {
System.loadLibrary("udt");
System.loadLibrary("udtrecvfile");
}
在工程目录下的properties文件的末尾加上一句:
Android.useDeprecatedNdk=true
在文件gradle(Module:app)里面的buildTypes类中添加一个这样的方法
sourceSets {
main {
jni.srcDirs = []
}
}
编译,运行,测试
这是我第一次用github,如有问题请多多指教,谢谢
参考资料: