【原创】NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战

概述

本文演示的是一个Android客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo

当前由于NIO框架的流行,使得开发大并发、高性能的互联网服务端成为可能。这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2、而Netty的主要版本是Netty3Netty4Netty5已经被取消开发了详见此文)。

本文中,服务端将分别用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 推荐

《NIO框架入门》系列文章目录

有关MINA和Netty的入门文章很多,但多数都是复制、粘贴的未经证实的来路不明内容,对于初次接触的人来说,一个可以运行且编码规范的Demo,显然要比各种“详解”、“深入分析”之类的要来的直接和有意义。本系列入门文章正是基于此种考虑而写,虽无精深内容,但至少希望对初次接触MINA、Netty的人有所启发,起到抛砖引玉的作用。

本文是《NIO框架入门》系列文章中的第 篇,目录如下:

本篇亮点

  • 客户端基于Android移动端平台:
    直接使用Android的标准UDP代码,不依赖第3方包,且已解决与Java NIO服务端的跨平台通信问题,是个难得的Android端实践入门示例;
  • 完整可执行源码、方便学习:
    完整的Demo源码,适合新手直接运行,便于学习和研究。
  • Demo中的代码源自作者的开源工程,有实用价值:
    源码均修改自作者的即时通讯开源工程 MobileIMSDK,只是为了方便学习理解而作了简化,有一定的实用价值;

本文中Demo演示的功能

本文中的Demo代码实现包含两部分,Android UDP客户端和NIO框架实现的服务端(包括MINA2和Netty4实现两个方案),客户端每隔5秒向服务端发送消息,而服务端在收到消息后马上回复一条消息给客户端。

如上所述,服务端(PC服务器)和客户端(Android移动端)都要实现消息的发送和接收,即实现跨平台的双向通信。下节将将给出真正的实现代码。

Android客户端准备工作

[Step 1]:准备好开发环境

这两年,Google官方已经基本放弃Eclipse+ADT这样的IDE组合,转而大力开发Android Studio,但不得不承认,由于我的OS仍然是XP(Android Studio不支持XP),所以Eclipse+ADT还得继续用(这个组合虽然一直被吐槽,但又不得不用)。

如果你习惯使用Eclipse+ADT这样的IDE,可以下载我打好包的版本,内含Eclipse4.2+ADT+Android SDK:


如果你需要Android Studio,可进入此链接下载

[Step 2]:新建一个普通的Android工程,准备开撸

本文以Eclipse+ADT为开发Android开发工具(如你使用Android Studio道理也是一样的),按照提示新建工程即可,无需特殊的设置或其它前前置条件。

我建好的工程,如下图所示(很多都是默认生成的,用不上的东西就别去管它了):


补充说明:因为需要进行网络通信,建好的工程里,请务必在 AndroidManifest.xml 加上网络权限的许可,如下图:

Android客户端代码实现

[1] 客户端主类 MainActivity.java:

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输出哦。

[2] 客户端本地 UDP Socket 管理类 LocalUDPSocketProvider.java:

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);
                 }
         }
}

补充说明:

猜你喜欢

转载自jb2011.iteye.com/blog/2308368
今日推荐