学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为6389字,预计阅读11分钟
写在最前
前面的文章我们已经把C#通过NNanoMsg实现通讯的Demo说完了,本章开始介绍Android的通讯,通过NDK的方式主要是C++的调用,所以开始我们还是要先介绍一下怎么通过C或C++的调用NanoMsg。
NanoMsg相关函数
微卡智享
下面我们就列一下几个常用的函数,基本的通讯也就是用这几个函数进行处理的。
函数 | 简单介绍 |
---|---|
nn_socket | 创建一个套接字 |
nn_setsockopt | 设置套接字的选项 |
nn_bind | 绑定地址 |
nn_connect | 连接另一个套接字 |
nn_send | 发送数据 |
nn_recv | 接收数据 |
nn_socket
所在头文件:#include <nanomsg/nn.h>,作用为创建一个套接字。
int nn_socket (int domain, int protocol);
参数:
domain:这个参数有两个格式,AF_SP和AF_SP_RAW,AF_SP表示标准的格式,AF_SP_RAW表示一种原始的格式,一般开发使用AF_SP即可。
protocol:设置通讯协议类型。如NN_PAIR等。
返回值:返回套接字。
nn_setsockopt
所在头文件:#include <nanomsg/nn.h>,作用和原始socket开发中的setsockopt类似,用来设置套接字的选项。
int nn_setsockopt (int s, int level, int option, const void *optval, size_t optvallen);
参数:
s:上面的函数nn_socket的返回值;
level:默认正常0即可(即NN_SOL_SOCKET);
option:需要改变的选项,一般我们来说主要就是设置超时这块的设置(即NN_SNDTIMEO和NN_RCVTIMEO);
*optval:上一个option参数对应的值;
optvallen:上一个*optval参数的长度;
返回值:返回不为零表示失败。
nn_bind
所在头文件:#include <nanomsg/nn.h>,作用绑定地址。
int nn_bind (int s, const char *addr);
参数:
s:上面的函数nn_socket的返回值;
*addr:地址;
返回值:返回小于零表示失败。
nn_connect
所在头文件:#include <nanomsg/nn.h>,作用连接另一个套接字。
int nn_connect(int s, const char *addr);
参数:
s:上面的函数nn_socket的返回值;
*addr:连接的地址;
返回值:返回小于零表示失败。
nn_send
所在头文件:#include <nanomsg/nn.h>,作用发送数据。
int nn_send (int s, const void *buf, size_t len, int flags);
参数:
s:上面的函数nn_socket的返回值;
*buf:发送的数据;
len:发送数据的长度;
flags:0表示在阻塞模式下执行,1(NN_DONTWAIT),表示在非阻塞模式下执行。
返回值:返回发送数据的长度,小于零表示错误。
nn_recv
所在头文件:#include <nanomsg/nn.h>,作用接收数据。
int nn_recv(int s,void * buf,size_t len,int flags);
参数:
s:上面的函数nn_socket的返回值;
*buf:接收的数据;
len:接收数据的最大长度;
flags:0表示在阻塞模式下执行,1(NN_DONTWAIT),表示在非阻塞模式下执行。
返回值:返回接收到的数据长度。
Android的NDK的简单调用
微卡智享
我们用Android Studio新建了一个C++的项目名称为AndroidNanoMsg
配置CMakeList中我们要指定上一篇《NanoMsg框架|Android Studio编译NanoMsg源码》编译的动态库的路径,根据自己设置的路径自行修改,这里是我自己的路径D:\Business\DemoTEST\nanomsgtest\NanoMsg4Android\MakeNanomsgLib,所以我就要改为这个,如果你自己的不同这里也进行修改
# For more information about using CMake with Android Studio, read the# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
#定义程序的目录,后面通过这个来关键编译好的动态库和头文件#我们自己如果要修改目录只改这个地方就可以了set(nanomsgpath "D:/Business/DemoTEST/nanomsgtest/NanoMsg4Android/MakeNanomsgLib/app")
#定义库文件的目录set(nanomsglibpath ${nanomsgpath}/build/intermediates/cmake/debug/obj)
#调用头文件的具体路径include_directories(${nanomsgpath}/src/main/cpp/src)include_directories(${nanomsgpath}/src/main/cpp/src/utils)
#增加我们的动态库add_library(libnanomsg SHARED IMPORTED)
#建立链接set_target_properties(libnanomsg PROPERTIES IMPORTED_LOCATION "${nanomsglibpath}/${ANDROID_ABI}/libnanomsg.so")
# Creates and names a library, sets it as either STATIC# or SHARED, and provides the relative paths to its source code.# You can define multiple libraries, and CMake builds them for you.# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library. native-lib
# Sets the library as a shared library. SHARED
# Provides a relative path to your source file(s). native-lib.cpp)
# Searches for a specified prebuilt library and stores the path as a# variable. Because CMake includes system libraries in the search path by# default, you only need to specify the name of the public NDK library# you want to add. CMake verifies that the library exists before# completing its build.
find_library( # Sets the name of the path variable. log-lib
# Specifies the name of the NDK library that # you want CMake to locate. log)
# Specifies libraries CMake should link to your target library. You# can link multiple libraries, such as libraries you define in this# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library. native-lib libnanomsg
# Links the target library to the log library # included in the NDK. ${log-lib})
在build.gradle主要就是加上动态库的SourceSets,这样打包的时候会一起加入进去
android { compileSdkVersion 29 buildToolsVersion "29.0.2" defaultConfig { applicationId "dem.vac.androidnanomsg" minSdkVersion 14 targetSdkVersion 29 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "-std=c++11" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt"
} }
//加上 sourceSets{ main{ //当前这个目录下的库文件会被调用并且被打包进apk中 jniLibs.srcDirs = ['D:/Business/DemoTEST/nanomsgtest/NanoMsg4Android/MakeNanomsgLib/app/build/intermediates/cmake/debug/obj'] } }
}
通过上面两步,我们NDK的基本配置就完成了,接下来我们就开始做PAIR的测试。
下面是一个简单的PAIR的调用方法,写在了一nanomsgtest方法中
extern "C" JNIEXPORT jstring JNICALLJava_dem_vac_nanomsgdemo_MainActivity_nanomsgtest (JNIEnv *env, jobject, jstring ipadr_, jstring sendmsg_) {
char *reschar; //设置超时地址 int timeo = 5000;
//获取地址 const char *ipadress = env->GetStringUTFChars(ipadr_, 0); const char *ipadrpre = "tcp://";
//拼接地址 int len = strlen(ipadress) + strlen(ipadrpre); char str[len]; strcpy(str, ipadrpre); strcat(str, ipadress);
//获取发送字符串 const char *sendmsg = env->GetStringUTFChars(sendmsg_, 0);
try { //创建PAIR的套接字 int pair_socket = nn_socket(AF_SP, NN_PAIR); if (pair_socket == -1) { throw "nn_socket failed! error"; }
//设置超时 int rc; rc = nn_setsockopt(pair_socket, 0, NN_SNDTIMEO, &timeo, sizeof(timeo)); rc = nn_setsockopt(pair_socket, 0, NN_RCVTIMEO, &timeo, sizeof(timeo));
//连接服务器 rc = nn_connect(pair_socket, str); if (rc < 0) { throw "nn_connect failed! error"; }
char buf[256] = {0}; //计算长度 int str_len = strlen(sendmsg); //将sendmsg复制到buf中 memcpy(buf, sendmsg, str_len);
//发送数据 rc = nn_send(pair_socket, buf, str_len, 0); if (rc < 0) { throw "nn_send failed! error"; }
//接收数据 char buffer[256]; rc = nn_recv(pair_socket, buffer, 256, 0); if (rc < 0) { throw "nn_recv failed! error"; }
char bufrecv[250] = {0}; //将sendmsg复制到buf中 memcpy(bufrecv, buffer, rc);
reschar = bufrecv; LOGI("%s\n", reschar);
memset(buffer, 0, 256); //关闭套接字 nn_close(pair_socket); } catch (char *e) { reschar = e; } return env->NewStringUTF(reschar);}
对应的MainActivity中
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main)
// Example of a call to a native method sample_text.text = stringFromJNI()
btnsend.setOnClickListener { var resstr = "" try { sample_text.text = "通讯中" var ipadr = edtipadr.text.toString() var sendmsg = "我发个试试"; resstr = nanomsgtest(ipadr, sendmsg) sample_text.text = resstr } catch (e: Exception) { Log.i("ndk", e.message) sample_text.text = e.message }
} }
/** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ external fun stringFromJNI(): String
external fun nanomsgtest(ipadr: String, sendmsg: String): String
companion object {
// Used to load the 'native-lib' library on application startup. init { System.loadLibrary("native-lib") } }}
按上面的写法,一个简单的NanoMsg的调用就已经实现了,下一篇我们来写一下关于NanoMsg在NDK中的简单的封装,方便不会NDK的同学直接调用。
完