最近弄了一个UDP/TCP的小东西,主要需要实现的功能如下(服务器端):

1、基于局域网

2、服务器端网络接口为无线与有线

3、服务器端接收到客户端的数据需要模拟按键进行处理

4、开机自启动

5、使用UDP进行连接,TCP进行通讯

基于以上几点,我们开始分析:

1.需要获取当前的网络IP地址,这里枚举了本机所有的网络地址,只返回ipv4

 1 public String getAddressIP() {
 2         //检查网络是否连接
 3         while (!isNetWorkConnected()) {
 4             //等待网络连接
 5         }
 6         ip = getLocalIpAddress();
 7         return ip;
 8     }
 9
10     public String getLocalIpAddress() {
11         String address = null;
12           try {
13             for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
14               NetworkInterface intf = en.nextElement();
15               for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
16                 InetAddress inetAddress = enumIpAddr.nextElement();
17                 if (!inetAddress.isLoopbackAddress()) {//127.0.0.1
18                     address = inetAddress.getHostAddress().toString();
19                     //ipV6
20                     if(!address.contains("::")){
21                         return address;
22                     }
23                 }
24               }
25             }
26           } catch (SocketException ex) {
27               Log.e("getIpAddress Exception", ex.toString());
28           }
29           return null;
30         }
31
32     private boolean isNetWorkConnected() {
33         // TODO Auto-generated method stub
34         try{
35             connectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
36             if(connectivity != null){
37                 netWorkinfo = connectivity.getActiveNetworkInfo();
38                 if(netWorkinfo != null && netWorkinfo.isAvailable()){
39                     if(netWorkinfo.getState() == NetworkInfo.State.CONNECTED){
40                         isConnected = true;
41                         return true;
42                     }
43                 }
44             }
45         }catch(Exception e){
46             Log.e("UdpService : ",e.toString());
47             return false;
48         }
49         return false;
50     }

2.获得IP之后,创建一个多播组

 1       try {
 2
 3             while(ip == null){
 4                 ip = getAddressIP();
 5             }
 6
 7             inetAddress = InetAddress.getByName(BROADCAST_IP);//多点广播地址组
 8             multicastSocket = new MulticastSocket(BROADCAST_PORT);//多点广播套接字
 9             multicastSocket.setTimeToLive(1);
10             multicastSocket.joinGroup(inetAddress);
11
12         } catch (UnknownHostException e) {
13             e.printStackTrace();
14         } catch (IOException e) {
15             e.printStackTrace();
16         }

这里设置一组特殊网络地址作为多点广播地址,第一个多点广播地址都被看作是一个组,当客户端需要发送接收广播信息时,加入该组就可以了。

IP协议为多点广播提供这批特殊的IP地址,这些IP地址范围是224.0.0.0---239.255.255.255,其中224.0.0.0为系统自用。

下面BROADCAST_IP是自己声明的一个String类型的变量,其范围也是前面所说的IP范围,比如BROADCAST_IP="224.224.224.224"。

1     private static int BROADCAST_PORT = 1234;
2     private static int PORT = 4444;
3     private static String BROADCAST_IP = "224.0.0.1";

3.服务端开始发送本机IP地址广播,如果网络断开,则结束掉此线程,并设置标识

 1     public class UDPBoardcastThread extends Thread {
 2         public UDPBoardcastThread() {
 3             this.start();
 4         }
 5
 6         @Override
 7         public void run() {
 8             DatagramPacket dataPacket = null;
 9             //将本机的IP地址放到数据包里
10             byte[] data = ip.getBytes();
11             dataPacket = new DatagramPacket(data, data.length, inetAddress, BROADCAST_PORT);
12             //判断是否中断连接了
13             while (isNetWorkConnected()) {
14                 try {
15                     multicastSocket.send(dataPacket);
16                     Thread.sleep(5000);
17                     Log.i("UDPService:","再次发送ip地址广播");
18                 } catch (Exception e) {
19                     e.printStackTrace();
20                 }
21             }
22             isConnected = false;
23             Message msg = new Message();
24             msg.what = 0x0001;
25             mHandler01.sendMessage(msg);
26
27         }
28     }

4.新开一个线程,等待客户端连接,使用TCP进行通讯

 1             new Thread() {
 2                 @Override
 3                 public void run() {
 4                     try {
 5                     //建立一个线程池,每次收到一个客户端,新开一个线程
 6                     mExecutorService = Executors.newCachedThreadPool();
 7                     Socket client = null;
 8                     mList.clear();
 9                     while (isConnected) {
10
11                         client = server.accept();
12                         //把客户端放入客户端集合中
13                         if (!connectOrNot(client)) {
14                             mList.add(client);
15                             Log.i("UDPService","当前连接数:"+mList.size());
16                         }
17                         mExecutorService.execute(new Service(client));
18                     }
19                     //释放客户端
20                     for(int i = 0 ; i < mList.size() ; i++)
21                         mList.get(i).close();
22
23                     } catch (IOException e) {
24                         e.printStackTrace();
25                     }
26                 }
27             }.start();

5.新开一个客户端的线程,处理客户端发送过来的数据等

 1     //客户端线程,组成线程池
 2     class Service implements Runnable {
 3         private Socket socket;
 4         private BufferedReader in = null;
 5         private String msg = "";
 6
 7         public Service(Socket socket) {
 8             this.socket = socket;
 9         }
10
11         @Override
12         public void run() {
13             try {
14                 in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
15                 //等待接收客户端发送的数据
16                 while (isConnected) {
17
18                     if ((msg = in.readLine()) != null) {
19
20                         // 创建一个Instrumentation对象,调用inst对象的按键模拟方法
21                         Instrumentation inst = new Instrumentation();
22                         try{
23                             int codeKey = Integer.parseInt(msg);
24                             //codeKey对应键值参照KeyCodeTable.txt文件,在客户端中实现
25                             inst.sendKeyDownUpSync(codeKey);
26
27                             //发送回执
28                             this.sendmsg(socket);
29                         }catch(Exception ex){
30                             ex.printStackTrace();
31                         }
32
33                     }
34                 }
35             } catch (Exception e) {
36                 e.printStackTrace();
37             }
38         }
39
40         private void sendmsg(Socket socket2) {
41             // TODO Auto-generated method stub
42             PrintWriter pout = null;
43
44             try {
45                 pout = new PrintWriter(new BufferedWriter(
46                         new OutputStreamWriter(socket2.getOutputStream())), true);
47                 pout.println("I am ok");
48             } catch (IOException e) {
49                 // TODO Auto-generated catch block
50                 e.printStackTrace();
51             }
52
53         }
54
55     }

这里使用了Instrumentation()对象来模拟按键的处理,在实际使用中,效率还行,没有很严重的延时,若真有延时,感觉也是网络方面的。

使用了socket.getInputStream()与socket.getOutputStream()方法来进行socket数据的接收与发送

6.最后新开一个Handler对网络断开时进行处理,也可以监听系统网络变化的广播,有时间研究下service的生命周期

 1     private Handler mHandler01 = new Handler(){
 2
 3         @Override
 4         public void handleMessage(Message msg) {
 5             // TODO Auto-generated method stub
 6             super.handleMessage(msg);
 7             switch(msg.what){
 8             //连接失败
 9             case 0x0001:
10                 initData();
11                 break;
12             }
13         }
14
15     };

7.开机自启动,继承BroadcastReceiver,监听系统开机广播就ok了,记得在AndroidManifest.xml文件中声明BOOT_COMPLETED属性

1     if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")){
2             Intent intent2 = new Intent(context, UdpService.class);
3             context.startService(intent2);
4         }

8.还有一个问题,如果我们就这样直接编译,输出apk到电视中,会出现权限不足的error,原因是apk不是系统应用,只有uid为system id才可以去模拟按键事件,所以在

AndroidManifest.xml中加上android:sharedUserId="android.uid.system",以及<uses-permission android:name="android.permission.INJECT_EVENTS" />

再编写Android.mk,最后在android源码中使用mm命令编译apk,这样就ok了。

服务器端的流程差不多是这样了,附上完整源码,包含服务器端与客户端Demo:

http://download.csdn.net/detail/u012062785/9684842

thread与runnable的区别:https://www.oschina.net/question/565065_86563

转载于:https://www.cnblogs.com/pngcui/p/6068983.html

Android开发之无线遥控器相关推荐

  1. Android环境搭建和Android HelloWorld—Android开发环境搭建

    Android_Android开发环境搭建-搭建Android的开发环境 1.我考虑先下载JDK7.0,在JDK的安装中,考虑一般SDK都是向上兼容的,于是选择了最高的版本7.0 这里是我总结的详细的 ...

  2. java安卓开发工具_推荐几个非常实用的Android开发工具

    工欲善其事,必先利其器.我们进行Android开发也要有好的开发工具辅助才能更好更高效的完成各种开发,为用户提供更实用的应用程序.本文就为大家推荐几个非常实用的Android开发工具,及几个常用的编辑 ...

  3. android 网络编程实现,Android开发使用HttpURLConnection进行网络编程详解【附源码下载】...

    本文实例讲述了Android开发使用HttpURLConnection进行网络编程.分享给大家供大家参考,具体如下: --HttpURLConnection URLConnection已经可以非常方便 ...

  4. linux 浏览器源码下载,Android开发:图片浏览器源码

    Android 图片浏览器源码,是你学习Android很好的例子,希望对你的学习有帮助. main.xml android:layout_width="fill_parent" a ...

  5. 2017-2018-2 20165236 实验四《Android开发基础》实验报告

    2017-2018-2 20165236 实验四<Android开发基础>实验报告 一.实验报告封面 课程:Java程序设计       班级:1652班       姓名:郭金涛     ...

  6. Android开发权威指南(第2版)新书发布

    <Android 开发权威指南(第二版)>是畅销书<Android开发权威指南>的升级版,内容更新超过80%,是一本全面介绍Android应用开发的专著,拥有45 章精彩内容供 ...

  7. indows上的android开发环境软件架构5

    (二)实验要求: ? 修改按下button 显示的内容中添加上自己的学号姓名: ? 添加一个按钮,按钮名称为"退出",并且为这个按钮添加事件代码,使得点击这个按钮后退 出程序.事件 ...

  8. 折叠屏就要来了,适配逼死 Android 开发?

    1. 异型屏还没适配好,折叠屏就要来了,Android 的碎片化,让开发者又多掉了不少头发. 北京时间 11 月 8 日,三星在旧金山向开发者发布了一款可折叠屏幕手机.并表示,新技术需要开发者调整其 ...

  9. 《ArcGIS Runtime SDK for Android开发笔记》——(6)、基于Android Studio的ArcGIS Android工程结构解析...

    1.前言 Android Studio 是第一个Google官方的 Android 开发环境.其他工具,例如 Eclipse,在 Android Studio 发布之前已经有了大规模的使用.为了帮助开 ...

最新文章

  1. redhat nginx php mysql_redhat7+nginx+mysql+php
  2. php里isset的属性,测试PHP中变量是否存在的最佳方法;isset()显然已损坏
  3. 会计行业被计算机取代马云,会计人:为什么我神烦“人工智能取代说”?
  4. 使用RMAN传输表空间复制数据
  5. 熊猫分发_熊猫下降列和行
  6. 对于scanf的新理解
  7. MVC学习笔记三:WebGrid控件的简单使用
  8. 美团斗鱼百度笔试概录
  9. 白话区块链~Pow,PoS,DPos
  10. 使用SSH工具链接本地虚拟机
  11. 虚拟机win 7 上安装VWware Tools提示升级系统到SP1
  12. win7电脑怎样修改环境变量
  13. 【python学习】python的面向对象编程
  14. kettle报错 Driver class ‘org.gjt.mm.mysql.Driver‘ could not be found, make sure the ‘MySQL‘ driver
  15. BOXI3 SDK 检索所有使用了某个universe object的报表
  16. 栈和队列的区别与栈和堆的区别
  17. java.lang.RuntimeException: java.lang.RuntimeException: org.codehaus.plexus.component.repository.exc
  18. 【吴恩达机器学习笔记】第十一章 机器学习系统的设计
  19. 特效师新人作品指引。
  20. UL1017是什么标准?吸尘器UL1017报告

热门文章

  1. 易语言发信服务器没有反应,还不会使用易语言连接发信服务器发送邮件的朋友看过来...
  2. [讲座论坛] 经济林之核桃类
  3. mysql好考还是office好考_计算机二级最好考哪个 office难考吗
  4. 《孤独六讲》-蒋勋 摘录2
  5. Microsoft Office Word 2003 稿纸加载项卸载不了 怎么处理
  6. cache相关概念及工作原理介绍
  7. Unity 动态生成球体模型
  8. 饿了么多人订餐时计算费用bug(饿了么商品促销优惠金额分摊计算规则)
  9. 华为云 · 云桌面 Workspace(介绍)
  10. jquery日历插件 途牛_11个实用jQuery日历插件