Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

[JNI] 开发实例(2) 编译libwebsocket,封装jni函数,搭建IM通信基础服务

$
0
0

WebSocket协议是基于TCP的一种新的协议。WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符。它实现了浏览器与服务器全双工(full-duplex)通信。这段介绍来自百科。

当然websocket也可以用于android建立长链接,实现IM通信
优势:节省内存空间。当然这个是服务端并发时候节省内存空间,支持的并发量更大 ,这个我没做服务端没有验证。

原理和优势不再本文讨论范围内,今天主要记录下怎么编译libwebsocket.so

1.下载Libwebseocket库

git clone https://github.com/warmcat/libwebsockets.git

2.环境准备(Mac版)

2.1安装zlib :

brew install zlib

2.2安装makedepend:

brew install makedepend

2.3安装cmake :

brew install cmake

3.编译.a静态文件

有了上面这些工具,准备工作差不多了,然后通过libwebsocket/contrib目录下的android-make-script.sh编译.a文件 这个sh文件有些问题,比如:只能编译出arm架构的文件,并且在编译zlib库时使用的libtool有问题,libwebsocket原文件编译出错。

针对这些问题作了一些修改:

3.1 修改output.c和http2.c原文件编译错误,这个已经提交到libwebsocket base2.2版本上了

 https://github.com/warmcat/libwebsockets/commit/34842d7492b728349f6a6898e3893b08d70625fa

3.2 替换libtool文件

mv ./Makefile ./Makefile.old
sed "s/AR=libtool/AR=`echo ${AR}|sed 's#\/#\\\/#g'`/" ./Makefile.old > Makefile.mid
sed "s/ARFLAGS=-o/ARFLAGS=-r/" ./Makefile.mid > Makefile

3.3 增加build x86架构文件编译

android支持的架构不光是arm,还有x86 x86-64等架构的机器,常用的armabi 和x86 这里提供了编译方式 如果还需要其他架构的可以根据android-make-script-all.sh文件 修改对应的参数
其他架构的参数可以在原始项目的test-server中的NativeLibs.mk中找到,然后修改android-make-script-all.sh文件

4.JNI封装websocket.

4.1初始化 initLws

初始化context
先准备好必要的参数 :host ,port ,path,timeout, ping,ca cert
涉及到函数:

jni_setConnectionParameters // host port path
jni_setTimeout  //超时
jni_setPingInterval //ping 间隔
jni_setCaCert //证书

然后调用lws_create_context初始化context

jni_initLws

4.2连接 connect

当context初始化后,就可以连接服务器了

jni_connectLws

在jni_connectLws调用lws_client_connect_via_info连接服务器

还有一个重要的函数

jni_serviceLws

这个方法的作用是,轮训,不断的去检查是否有消息接收,检查到有新消息到达,通过callback回调,然后通过receiveMessage回调到java层

4.3发送/接收消息 writeLws/callback

接收消息

我们在初始化context时注册了一个协议,这个protocol中包含一个callback,我们就是通过这个callback来接收服务端的消息,及错误信息

static int callback(
        struct lws *wsi,
        enum lws_callback_reasons reason,
        void *user,
        void *in,
        size_t len
) {
    //
    return 0;
}

只需要关注下面两个参数

reason:回执code 
in :消息体

发送消息

jni_sendMessageLws

调用的lws_write来发送消息,这里要注意的是发送消息的大小(初始化时候设置的),如果超过这个大小消息会分片,分片的消息需要自行处理,在callback中LWS_CALLBACK_SERVER_WRITEABLE处理剩下的报文。
当然我们平时发送的消息体不会太大,一般几百个字节最够了,我这里设置的4K
够发1500+个汉字。

4.4断开 exitLws

调用lws_context_destroy断开连接

重要函数参数:

状态值 含义
LWS_CALLBACK_WSI_CREATE 含义:正在创建ws连接对象备注:此时表1中wsi对象和user对象依然为空指针,因此,还不能初始化用户自定义对象。回调函数的参数含义: context: 全局上下文 wsi: 空指针 user: 空指针 in: 空指针len: 0
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION 使用lws库的人员可以在此过滤协议。备注:在此处返回非0值时,lws库将会关闭该链接;该处返回0时,表示ws连接已经建立成功。此时表1中的wsi对象和user对象已不为空,因此,此时可以对用户自定义对象user进行初始化处理。
LWS_CALLBACK_RECEIVE 表示WS服务端收到客户端发送过来的一帧完整数据,此时表1中的in表示收到的数据,len表示收到的数据长度。需要注意的是:指针in的回收、释放始终由LWS框架管理,只要出了回调函数,该空间就会被LWS框架回收。因此,开发者若想将接收的数据进行转发,则必须对该数据进行拷贝
LWS_CALLBACK_CLOSED ws连接已经断开 备注:不能在此释放内存空间,否则存在内存泄漏的风险!!!因为连接断开时,并不总是会回调LWS_CALLBACK_CLOSED的处理!
LWS_CALLBACK_WSI_DESTROY 正在销毁ws连接对象 表示libwebsockets框架即将销毁wsi对象。此时如果用户自定义对象中存在动态分配的空间,则需要在此时进行释放


重要函数:

状态值 功能
lws_send_pipe_choked 功能:判断ws连接是否阻塞 备注:如果ws连接阻塞,则返回1,否则返回0
lws_create_context 功能:初始化websocket服务,返回context 如果不为null 初始化成功
lws_client_connect_via_info 功能:建立websocket连接 ,返回wsi 如果不为null 连接成功
lws_write 功能:将数据发送给对端 备注:函数参数说明 wsi: ws连接对 buf: 需要发送数据的起始地址 返回:result > 0 成功,result = 0 失败
lws_callback_on_writable 将ws连接加入可写事件监听
lws_service 检查是否有新消息接收
lws_context_destroy 断开websocket服务


5.搭建简易服务端测试

进入到python服务器所在目录 运行下面命令 启动python服务器

python testServer.py 

这个py服务器比较简单,只能支持1024字节传输,超过这个长度会乱码,要测试超长字符,服务器还是要自己去搭建。

通过上面的步骤,就可以编译了下面是我编译好的源码及demo,有需要可以下载

https://github.com/honjane/buildLibWebSocket

demo使用步骤:

1.进入buildws目录,运行sh文件 生成.a文件,然后把生成的.a文件拷贝到websocket/src/main/jni/ 对应架构下 libcrypto.a libssl.a libwebsocket.a libz.a

2.使用build-ndk 编译 jni目录生成对应libwebsocket.so 怎么编译就不多说,生成的so文件会在libs和obj目录下,把这些生存的so拷贝到jniLibs/对应架构下目录

3.启动python服务器 ,连接服务器,发送消息

作者:tsdfk1455 发表于2017/4/8 16:55:00 原文链接
阅读:106 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>