学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为6389字,预计阅读11分钟
写在最前
前面的文章我们已经把C#通过NNanoMsg实现通讯的Demo说完了,本章开始介绍Android的通讯,通过NDK的方式主要是C++的调用,所以开始我们还是要先介绍一下怎么通过C或C++的调用NanoMsg。
NanoMsg相关函数
![](https://i-blog.csdnimg.cn/blog_migrate/3c49773a66a660b04cbe2b89c3b9f137.png)
微卡智享
下面我们就列一下几个常用的函数,基本的通讯也就是用这几个函数进行处理的。
函数 | 简单介绍 |
---|---|
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的简单调用
![](https://i-blog.csdnimg.cn/blog_migrate/3c49773a66a660b04cbe2b89c3b9f137.png)
微卡智享
我们用Android Studio新建了一个C++的项目名称为AndroidNanoMsg
配置CMakeLists
配置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
在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的测试。
C++中的调用方法
下面是一个简单的PAIR的调用方法,写在了一nanomsgtest方法中
extern "C" JNIEXPORT jstring JNICALL
Java_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的同学直接调用。
完
扫描二维码
获取更多精彩
微卡智享
「 往期文章 」
NanoMsg框架|Android中简单封装PAIR的使用(附Demo地址)