标签:
本文演示的是一个Android客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo。
当前由于NIO框架的流行,使得开发大并发、高性能的互联网服务端成为可能。这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2、而Netty的主要版本是Netty3和Netty4(Netty5已经被取消开发了:详见此文)。
本文中,服务端将分别用MINA2和Netty4进行实现,但在你实际的项目中服务端实现只需选其一就行了。本文中的Demo同时用MINA2和Netty4分别实现服务端的目的,是因为很多人都在纠结到底是用MINA还是Netty来实现高并发的Java网络通信服务端,在此干脆两个都实现了,就看你怎么选择。
实际上,MINA2和Netty4的官方代码里有UDP通信的Demo代码,但却不存在针对移动端(主要是Android和iOS端)的Demo,本文将演示用Android客户端来实现这种跨平台的双向网络通信。Demo中,已经解决跨平台通信时的常见的乱码、数据字节异常等问题,如觉得有用,你可直接使用之。
- 更多即时通讯技术资料:http://www.52im.net/forum.php?mod=collection&op=all
- 移动端即时通讯交流群:215891622 推荐
有关MINA和Netty的入门文章很多,但多数都是复制、粘贴的未经证实的来路不明内容,对于初次接触的人来说,一个可以运行且编码规范的Demo,显然要比各种“详解”、“深入分析”之类的要来的直接和有意义。本系列入门文章正是基于此种考虑而写,虽无精深内容,但至少希望对初次接触MINA、Netty的人有所启发,起到抛砖引玉的作用。
本文是《NIO框架入门》系列文章中的第 4 篇,目录如下:
本文中的Demo代码实现包含两部分,Android UDP客户端和NIO框架实现的服务端(包括MINA2和Netty4实现两个方案),客户端每隔5秒向服务端发送消息,而服务端在收到消息后马上回复一条消息给客户端。
如上所述,服务端(PC服务器)和客户端(Android移动端)都要实现消息的发送和接收,即实现跨平台的双向通信。下节将将给出真正的实现代码。
这两年,Google官方已经基本放弃Eclipse+ADT这样的IDE组合,转而大力开发Android Studio,但不得不承认,由于我的OS仍然是XP(Android Studio不支持XP),所以Eclipse+ADT还得继续用(这个组合虽然一直被吐槽,但又不得不用)。
如果你习惯使用Eclipse+ADT这样的IDE,可以下载我打好包的版本,内含Eclipse4.2+ADT+Android SDK:
如果你需要Android Studio,可进入此链接下载。
本文以Eclipse+ADT为开发Android开发工具(如你使用Android Studio道理也是一样的),按照提示新建工程即可,无需特殊的设置或其它前前置条件。
我建好的工程,如下图所示(很多都是默认生成的,用不上的东西就别去管它了):
补充说明:因为需要进行网络通信,建好的工程里,请务必在 AndroidManifest.xml 加上网络权限的许可,如下图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
/* *
Copyright (C) 2016 即时通讯网(52im.net) - 即时通讯开发者社区. *
All rights reserved. */ package net.x52im.example.android.udp; import net.x52im.example.android.udp.utils.UDPUtils; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.ActionBarActivity; import android.util.Log; /** *
Demo主类。 * *
@author jack.jiang@52im.net, 2016-06-27 *
@version 1.0 */ public class MainActivity extends ActionBarActivity { private final static String
TAG = MainActivity. class .getSimpleName(); //
重复发送的时间间隔(单位:毫秒) public static int INTERVAL
= 5000 ; private Handler
handler = null ; private Runnable
runnable = null ; @Override protected void onCreate(Bundle
savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); //
初始化本地UDP的Socket LocalUDPSocketProvider.getInstance().initSocket(); //
启动本地UDP监听(接收数据用的) LocalUDPDataReciever.getInstance( this ).startup(); //
自动循环发送 handler
= new Handler(); runnable
= new Runnable(){ @Override public void run() { sendMessageToServer(); //
开始下一次循环 handler.postDelayed(runnable,
INTERVAL); } }; //
立即开始发送 handler.postDelayed(runnable, 0 ); } private void sendMessageToServer() { try { //
要发送的数据 String
toServer = "Hi,我是客户端,我的时间戳" +System.currentTimeMillis(); byte []
soServerBytes = toServer.getBytes( "UTF-8" ); //
开始发送 boolean ok
= UDPUtils.send(soServerBytes, soServerBytes.length); if (ok) Log.d(TAG, "发往服务端的信息已送出." ); else Log.e(TAG, "发往服务端的信息没有成功发出!!!" ); } catch (Exception
e) { Log.w(TAG,
e.getMessage(), e); } } } |
补充说明:本类没有去写UI代码,只是作为本次Demo的主入口类而已,需要查看数据输出的,请在Eclipse下的DDMS控制台看查看log输出哦。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
/* *
Copyright (C) 2016 即时通讯网(52im.net) - 即时通讯开发者社区. *
All rights reserved. */ package net.x52im.example.android.udp; import net.x52im.example.android.udp.utils.UDPUtils; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.ActionBarActivity; import android.util.Log; /** *
Demo主类。 * *
@author jack.jiang@52im.net, 2016-06-27 *
@version 1.0 */ public class MainActivity extends ActionBarActivity { private final static String
TAG = MainActivity. class .getSimpleName(); //
重复发送的时间间隔(单位:毫秒) public static int INTERVAL
= 5000 ; private Handler
handler = null ; private Runnable
runnable = null ; @Override protected void onCreate(Bundle
savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); //
初始化本地UDP的Socket LocalUDPSocketProvider.getInstance().initSocket(); //
启动本地UDP监听(接收数据用的) LocalUDPDataReciever.getInstance( this ).startup(); //
自动循环发送 handler
= new Handler(); runnable
= new Runnable(){ @Override public void run() { sendMessageToServer(); //
开始下一次循环 handler.postDelayed(runnable,
INTERVAL); } }; //
立即开始发送 handler.postDelayed(runnable, 0 ); } private void sendMessageToServer() { try { //
要发送的数据 String
toServer = "Hi,我是客户端,我的时间戳" +System.currentTimeMillis(); byte []
soServerBytes = toServer.getBytes( "UTF-8" ); //
开始发送 boolean ok
= UDPUtils.send(soServerBytes, soServerBytes.length); if (ok) Log.d(TAG, "发往服务端的信息已送出." ); else Log.e(TAG, "发往服务端的信息没有成功发出!!!" ); } catch (Exception
e) { Log.w(TAG,
e.getMessage(), e); } } } |
补充说明:以上代码使用的是Android的标准UDP Socket代码,如果你对此不太熟悉请先查阅更多Android UDP通讯的相关实例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
/* *
Copyright (C) 2016 即时通讯网(52im.net) - 即时通讯开发者社区. *
All rights reserved. */ package net.x52im.example.android.udp; import java.net.DatagramPacket; import java.net.DatagramSocket; import net.x52im.example.android.udp.utils.ConfigEntity; import android.content.Context; import android.util.Log; /** *
本地UDP端口监听和数据接收类。 * *
@author jack.jiang@52im.net, 2016-06-27 *
@version 1.0 */ public class LocalUDPDataReciever { private static final String
TAG = LocalUDPDataReciever. class .getSimpleName(); private static LocalUDPDataReciever
instance = null ; private Thread
thread = null ; private Context
context = null ; public static LocalUDPDataReciever
getInstance(Context context) { if (instance
== null ) instance
= new LocalUDPDataReciever(context); return instance; } private LocalUDPDataReciever(Context
context) { this .context
= context; } public void startup() { this .thread
= new Thread( new Runnable() { public void run() { try { Log.d(LocalUDPDataReciever.TAG, "本地UDP端口侦听中,端口=" +
ConfigEntity.localUDPPort + "..." ); //开始侦听 LocalUDPDataReciever. this .udpListeningImpl(); } catch (Exception
eee) { Log.w(LocalUDPDataReciever.TAG, "本地UDP监听停止了(socket被关闭了?)," +
eee.getMessage(), eee); } } }); this .thread.start(); } private void udpListeningImpl() throws Exception { while ( true ) { byte []
data = new byte [ 1024 ]; //
接收数据报的包 DatagramPacket
packet = new DatagramPacket(data,
data.length); DatagramSocket
localUDPSocket = LocalUDPSocketProvider.getInstance().getLocalUDPSocket(); if ((localUDPSocket
== null )
|| (localUDPSocket.isClosed())) continue ; //
阻塞直到收到数据 localUDPSocket.receive(packet); //
解析服务端发过来的数据 String
pFromServer = new String(packet.getData(), 0 ,
packet.getLength(), "UTF-8" ); Log.w(LocalUDPDataReciever.TAG, "【NOTE】>>>>>>
收到服务端的消息:" +pFromServer); } } } |
本文将分别基于MINA2和Netty4实现两套服务端(你只需要使用其中之一即可),服务端准备工作已在本系列文章的前两篇详细记录了,具体如下:
- Netty4实现服务端的准备工作请见:《NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示》
- MINA2实现服务端的准备工作请见:《NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示》
因两套方案的服务端代码都不复杂,且已经本系列文章的前两篇中详细介绍,本文就不在重复粘贴了。
- Netty4实现的服务端请见:《NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示》
- MINA2实现的服务端请见:《NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示》
[1] Android客户端运行结果:
[2] 服务端运行结果(MINA2方案):
[3] 服务端运行结果(Netty4方案):
Demo中的客户端代码是从开源即时通讯框架MobileIMSDK 的Android端中复制出来的(为了方便理解做了大幅简化),有兴趣的可看看
MobileIMSDK Android端、Server端,简化一下可以用作你自已的各种用途。
本文的姊妹篇《NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战》,演示的是iOS端的跨平台UDP双向通信,需要的话可以看看。
对于服务端的NIO框架来说,如果你阅读过本系列的《NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示》和《NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示》,应该能明显地感觉的出来MINA2的UDP服务端API接口使用要是Netty4的繁琐,而且MINA2还存在独立客户端(非依赖于MINA2客户端)实现时的多余字节和乱码问题。但个人认为MINA2的代码风格更符合一般程序员的编码习惯,更好懂一些,而Netty4因历经多个大版本的进化,虽起来非常简洁,但实现并不是那么直观。当然,至于MINA还是Netty,请客观一评估和使用,因为二者并无本质区别。
[1] MINA和Netty的源码在线学习和查阅:
MINA-2.x地址是:http://docs.52im.net/extend/docs/src/mina2/
MINA-1.x地址是:http://docs.52im.net/extend/docs/src/mina1/
Netty-4.x地址是:http://docs.52im.net/extend/docs/src/netty4/
Netty-3.x地址是:http://docs.52im.net/extend/docs/src/netty3/
[2] MINA和Netty的API文档在线查阅:
MINA-2.x API文档(在线版):http://docs.52im.net/extend/docs/api/mina2/
MINA-1.x API文档(在线版):http://docs.52im.net/extend/docs/api/mina1/
Netty-4.x API文档(在线版):http://docs.52im.net/extend/docs/api/netty4/
Netty-3.x API文档(在线版):http://docs.52im.net/extend/docs/api/netty3/
[3] 更多有关NIO编程的资料:
请进入精华资料专辑:http://www.52im.net/forum.php?mod=collection&action=view&ctid=9
[4] 有关IM聊天应用、消息推送技术的资料:
请进入精华资料专辑:http://www.52im.net/forum.php?mod=collection&op=all
[5] 技术交流和学习:
可直接进入 即时通讯开发者社区 讨论和学习网络编程、IM聊天应用、消息推送应用的开发。
如需完整Eclipse源码工程请联系作者,或者进入链接 http://www.52im.net/thread-388-1-1.html 自行下载。
完整源码工程截图如下:
截图说明:左右是Android客户端源码、右边是服务端(MINA2和Netty4两个方案)。
(本文同步发布于:http://www.52im.net/thread-388-1-1.html)
作者:Jack Jiang (点击作者姓名进入Github)
出处:http://www.52im.net/space-uid-1.html
联系方式:QQ: 413980957, 微信: hellojackjiang,Email: jb2011@163.com
Jack Jiang同时是【原创Java Swing外观工程BeautyEye】和【轻量级移动端即时通讯框架MobileIMSDK】的作者,可前往下载交流。
本博文 欢迎转载,转载请注明出处(也可前往 我的52im.net 找到我)。
【原创】NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战
标签:
原文地址:http://blog.csdn.net/jb2011000/article/details/51791958