本文长度为3287字,预计阅读8分钟
前言
接着上一篇《NanoMsg框架|Android Studio编译NanoMsg源码》来说的,我们介绍了Nanomsg的几个常用的函数,以及一段简单的调用代码,这篇我们介绍一下在Android下使用PAIR模式的简单封装。
实现效果
封装思路
微卡智享
# | 说明 |
---|---|
1 | 通过JNI把几个核心函数进行处理 |
2 | 把每种模式新建一个类用于单独处理相关的通讯 |
首先我们新建了一个NanoMsgJNI的类,这个类主要就是调用NDK的NanaMsg相关的函数,就是把几个最终会用到的函数bind,socket,connect,send,recv都加入进来提供外部调用。
package dem.vac.androidnanomsg
/**
* 作者:Vaccae
* 功能模块说明:
*/
class NanoMsgJNI {
companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("ndknanomsg")
}
}
//初始化Socket
external fun init(ntype: String): Int
//绑定地址
external fun bind(connectsocket: Int, ipadr: String): Int
//关闭套接了
external fun close(connectsocket: Int): Int
//连接数据库
external fun connect(connectsocket: Int, ipadr: String): Int
//发送数据
external fun send(connectsocket: Int, sendmsg: String): Int
//接收数据
external fun recv(connectsocket: Int): String
}
对应的native-lib中我们写入对应的函数方法,不知道什么原因,这里定义方法没法用ALT+ENTER进行自动创建了,所以我们方法都是自己手写的,如下
方法的命名规则就是Java_包名_类名_方法名
#include <jni.h>
#include <string>
#include <nn.h>
#include <stdio.h>
#include <protocol.h>
#include <pair.h>
#include <android/log.h>
// log标签
#define TAG "NanoErrInfo"
// 定义info信息
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
// 定义debug信息
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
// 定义error信息
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
//抛异常类标签
#define ERRCLS "java/lang/IllegalArgumentException"
//抛异常函数
void throwByName(JNIEnv *env, const char *name, const char *msg) {
jclass cls = env->FindClass(name);
if (cls != NULL) {
//检测是否有异常发生
if (0 != env->ExceptionOccurred()) {
//清除异常堆栈
env->ExceptionClear();
}
env->ThrowNew(cls, msg);
}
env->DeleteLocalRef(cls);
}
//获取NanoMsg连接类型
int getNanotype(const char *ntype) {
if (strcmp(ntype, "PAIR") == 0) {
return NN_PAIR;
} else {
return -1;
}
}
extern "C" JNIEXPORT jint JNICALL
Java_dem_vac_androidnanomsg_NanoMsgJNI_init(
JNIEnv *env,
jobject,
jstring ntype_
) {
int initsocket = -1;
//设置超时时间
int timeo = 100;
//获取连接方式
const char *ntype = env->GetStringUTFChars(ntype_, 0);
try {
initsocket = nn_socket(AF_SP, getNanotype(ntype));
if (initsocket < 0) {
throw initsocket;
}
//设置超时
nn_setsockopt(initsocket, 0, NN_SNDTIMEO, &timeo, sizeof(timeo));
nn_setsockopt(initsocket, 0, NN_RCVTIMEO, &timeo, sizeof(timeo));
}
catch (int e) {
char errmsg[100];
sprintf(errmsg, "创建Socket连接失败,返回码:%d", e);
LOGE("%s\n", errmsg);
throwByName(env, ERRCLS, errmsg);
}
//释放资源
env->ReleaseStringUTFChars(ntype_, ntype);
return initsocket;
}
extern "C" JNIEXPORT jint JNICALL
Java_dem_vac_androidnanomsg_NanoMsgJNI_bind(
JNIEnv *env,
jobject,
jint socketid_,
jstring ipadr_
) {
int bindsocket = -1;
//获取地址
const char *ipadress = env->GetStringUTFChars(ipadr_, 0);
const char *ipadrpre = "tcp://";
int len = strlen(ipadress) + strlen(ipadrpre);
char ipstr[len];
strcpy(ipstr, ipadrpre);
strcat(ipstr, ipadress);
try {
//绑定地址
bindsocket = nn_bind(socketid_, ipstr);
if (bindsocket < 0) {
throw bindsocket;
}
} catch (int e) {
char errmsg[100];
sprintf(errmsg, "绑定地址失败,返回码:%d", e);
LOGE("%s\n", errmsg);
throwByName(env, ERRCLS, errmsg);
}
//释放资源
env->ReleaseStringUTFChars(ipadr_, ipadress);
return bindsocket;
}
extern "C" JNIEXPORT jint JNICALL
Java_dem_vac_androidnanomsg_NanoMsgJNI_close(
JNIEnv *env,
jobject,
jint socketid_
) {
int closesocket = -1;
try {
//关闭套接字
closesocket = nn_close(socketid_);
if (closesocket != 1) {
throw closesocket;
}
} catch (int e) {
char errmsg[100];
sprintf(errmsg, "关闭套接字失败,返回码:%d", e);
LOGE("%s\n", errmsg);
throwByName(env, ERRCLS, errmsg);
}
return closesocket;
}
extern "C" JNIEXPORT jint JNICALL
Java_dem_vac_androidnanomsg_NanoMsgJNI_connect(
JNIEnv *env,
jobject,
jint socketid_,
jstring ipadr_
) {
int connectsocket = -1;
//获取地址
const char *ipadress = env->GetStringUTFChars(ipadr_, 0);
const char *ipadrpre = "tcp://";
int len = strlen(ipadress) + strlen(ipadrpre);
char ipstr[len];
strcpy(ipstr, ipadrpre);
strcat(ipstr, ipadress);
try {
//连接服务器
connectsocket = nn_connect(socketid_, ipstr);
if (connectsocket < 0) {
throw connectsocket;
}
} catch (int e) {
char errmsg[100];
sprintf(errmsg, "连接服务器失败,返回码:%d", e);
LOGE("%s\n", errmsg);
throwByName(env, ERRCLS, errmsg);
}
//释放资源
env->ReleaseStringUTFChars(ipadr_, ipadress);
return connectsocket;
}
extern "C" JNIEXPORT jint JNICALL
Java_dem_vac_androidnanomsg_NanoMsgJNI_send(
JNIEnv *env,
jobject,
jint socketid_,
jstring sendmsg_
) {
int count = 0;
//获取发送字符串
const char *sendmsg = env->GetStringUTFChars(sendmsg_, 0);
try {
//计算发送字节长度
int str_len = strlen(sendmsg);
//发送数据
count = nn_send(socketid_, sendmsg, static_cast<size_t>(str_len), 0);
if (count < 0) {
throw count;
}
} catch (int e) {
char errmsg[100];
sprintf(errmsg, "程序发送数据失败!返回码:%d", e);
LOGE("%s\n", errmsg);
throwByName(env, ERRCLS, errmsg);
}
//释放资源
env->ReleaseStringUTFChars(sendmsg_, sendmsg);
return count;
}
extern "C" JNIEXPORT jstring JNICALL
Java_dem_vac_androidnanomsg_NanoMsgJNI_recv(
JNIEnv *env,
jobject,
jint socketid_
) {
jstring recvmsg;
try {
int nbytes = 0;
//定义一个空指针
void *buf = NULL;
//接收数据
nbytes = nn_recv(socketid_, &buf, NN_MSG, 0);
if (nbytes < 0) {
throw nbytes;
} else {
recvmsg = env->NewStringUTF((char *) buf);
nn_freemsg(buf);
}
} catch (int e) {
char errmsg[100];
sprintf(errmsg, "接收数据失败!返回码:%d", e);
LOGE("%s\n", errmsg);
throwByName(env, ERRCLS, errmsg);
recvmsg = env->NewStringUTF("");
}
return recvmsg;
}
注意一下getNanotype这个方法,这里我们是在init主函数中传入的字符串,用于判断现在是什么模式的,我这里因为只做的PAIR,所以只写了这一个模式,后面的可以自己加入。
面两个其实就是把我们通过JNI调用NanoMsg的都已经简单的做好了,下一步我们就可以根据这里设置好的进行PAIR的操作了,
PAIR的封装
微卡智享
新建一个NNPAIR的类,主要就是保留当我们初始化后返回的套接字,所以定义了一个pairsocket,后面的操作都是根据传入这个套接字进行处理的。
package dem.vac.androidnanomsg
/**
* 作者:Vaccae
* 功能模块说明:
*/
class NNPAIR {
private var nnjni:NanoMsgJNI = NanoMsgJNI()
private var pairsocket: Int = -1
init {
if (pairsocket == -1) {
pairsocket = nnjni.init("PAIR")
}
}
//PAIR连接
fun connect(ipadr: String): Boolean {
val res = nnjni.connect(pairsocket, ipadr)
return res >= 0
}
//发送数据
fun send(sendmsg:String):Int{
return nnjni.send(pairsocket,sendmsg);
}
//接收数据
fun recv():String{
return nnjni.recv(pairsocket)
}
}
几行简单的代码就已经实现了,接下来就是在Activity中调用实现了
package dem.vac.androidnanomsg
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Adapter
import android.widget.ArrayAdapter
import android.widget.SpinnerAdapter
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private var nanotype = arrayOf("PAIR", "REQREP", "PUBSUB", "SURVEY")
private var nnpair: NNPAIR? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var adapter = ArrayAdapter(
this,
android.R.layout.simple_list_item_1, nanotype
)
spnnanotype.adapter = adapter
btnConnent.setOnClickListener {
if (nnpair == null) {
nnpair = NNPAIR()
}
nnpair.let {
if (it?.connect(edtipadr.text.toString())!!) {
tvmsg.text = "PAIR连接成功!\r\n"
} else {
tvmsg.text = "PAIR连接失败!\r\n"
}
}
}
btnSend.setOnClickListener {
nnpair.let {
try {
//发送数据
it?.send(edtinput.text.toString())
//延时50毫秒
Thread.sleep(50)
//接收数据
val recvmsg = it?.recv()
tvmsg.append(recvmsg + "\r\n")
} catch (e: IllegalArgumentException) {
tvmsg.append(e.message.toString() + "\r\n")
}
}
}
}
}
实现效果
Demo地址
https://github.com/Vaccae/NanoMsg4Android.git