搜索
bottom↓
回复: 8

android nio非阻塞多线程socket连接实现

[复制链接]

出0入0汤圆

发表于 2011-7-10 10:05:00 | 显示全部楼层 |阅读模式
费好大功夫凑的程序。在android平台实现网络连接。注释清楚,希望对我这样的没学过java的新人有点用。
package nio.socket.nei;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;

import android.app.Activity;

import android.os.Bundle;
import android.os.Handler;

import android.os.Message;

import android.widget.TextView;

public class niosocket extends Activity {
       
       
        //定义检测socketchannel的selector对象
        private Selector selector=null;
        //客户端socketchannel
        private SocketChannel sc=null;
    //定义处理编码和解码的字符集
        private Charset charset=Charset.forName("GBK");
        public TextView tv;
    /** Called when the activity is first created. */
    /**
     * 接受消息,处理消息 ,此Handler会与当前主线程一块运行
     * */

     Handler MyHandler=new Handler() {                       

         // 子类必须重写此方法,接受数据
         @Override
         public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Bundle b=msg.getData();
        String counnt=b.getString("colo");
        tv.setText(counnt);
         }
     };
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
      // bar=(ProgressBar) findViewById(R.id.progress);
       tv=(TextView)findViewById(R.id.text_view);
        try {
                //创建selector实例
                        selector=Selector.open();                       
                        InetSocketAddress isa=new InetSocketAddress("192.168.0.100",60000);       
                        //调用OPEn静态方法创建连接到指定主机的socketchannel
                        sc=SocketChannel.open(isa);
                        //设置SC为非阻塞方式工作
                        sc.configureBlocking(false);
                        //将sockchannel对象注_册到指定selector
                        sc.register(selector, SelectionKey.OP_READ);
                       
                        String line="连接成功";
                    sc.write(charset.encode(line));
                       
                } catch (IOException e) {
                        e.printStackTrace();
                }
      tv.setText("");   

       MyThread m = new MyThread();      
       new Thread(m).start();//启动线程      
      
      

    }
   
    class MyThread implements Runnable {
                   
                     public void run() {             
                         try {
                                 //监控所有注_册的channel,返回这里要处理channel的数量
                                 while(selector.select()>0)
                                 {
                                //处理每个有IO操作的集合
                                 for(SelectionKey sk:selector.selectedKeys())
                                 {   //删除正在处理的selectionkey
                                         selector.selectedKeys().remove(sk);
                                         //如果该selectionkey对应的channel中有可读的数据
                                         if(sk.isReadable())
                                         {
                                                 SocketChannel sc=(SocketChannel)sk.channel();
                                                 ByteBuffer buff=ByteBuffer.allocate(100);
                                                 String content="";
                                                 while(sc.read(buff)>0)
                                                 {//读出字节到缓存
                                                         sc.read(buff);
                                                         buff.flip();//反转缓存数据
                                                         content+=charset.decode(buff);
                                                 }
                                                 Message msg=new Message();
                                                 Bundle b=new Bundle();
                                                 b.putString("colo", content);
                                                 msg.setData(b);
                                                 MyHandler.sendMessage(msg);
                                                 //为下一次读取作准备
                                                 sk.interestOps(SelectionKey.OP_READ);
                                         }
                                 }
                                 }           
                                            }
                                 catch (IOException ex) {
                             ex.printStackTrace();
                         }             
                     }
                 }
    }

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果天空是黑暗的,那就摸黑生存;
如果发出声音是危险的,那就保持沉默;
如果自觉无力发光,那就蜷伏于牆角。
但是,不要习惯了黑暗就为黑暗辩护;
也不要为自己的苟且而得意;
不要嘲讽那些比自己更勇敢的人。
我们可以卑微如尘土,但不可扭曲如蛆虫。

出0入0汤圆

 楼主| 发表于 2011-7-10 10:07:12 | 显示全部楼层
要在androidManifest.xml里设置访问网络的权限,要不然连接时间会报错。
androidManifest.xml里加入:
</application>
      <uses-permission
     android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>     
    <uses-permission
     android:name="android.permission.INTERNET" />
</manifest>

出0入0汤圆

 楼主| 发表于 2011-7-10 17:48:58 | 显示全部楼层
以上程序是客户端,现在有个问题不知咋处理。
当客户端某种原因和服务器连接失败,我怎么能知道和服务器已经断开,我试验的貌似没啥反应,断开后发送数据,也没有异常。请高手帮忙指点一下。
当客户端掉线后,可以自动从新和服务器连接就行。

出0入0汤圆

发表于 2011-7-10 20:04:58 | 显示全部楼层
加入心跳协议哈.
像这类跨平台的网络通讯,我们这里主要用各种开源库来实现,首选boost的asio.
甚至我们的232短信猫也用asio来实现了.

出0入0汤圆

 楼主| 发表于 2011-7-12 17:51:19 | 显示全部楼层
加入心跳协议。我现在的问题是,连接好后,发送心跳包,如果发送失败,程序里是不是应该会报异常,是什么异常。我是不是可以在异常中从新连接。
在连接失败后,我发送5个心跳包,才会进入异常。感觉不太对。

出0入0汤圆

发表于 2014-5-29 19:50:15 | 显示全部楼层
不知楼主解决问题没有,我现在也在做这块,socket就死线程阻塞上,所以上NIO。结果情况也差不多,socket还能检测到服务器断开呢。

出0入0汤圆

发表于 2015-8-13 10:56:58 | 显示全部楼层
mark,刚接触这个,回头看

出0入0汤圆

发表于 2015-10-10 10:34:21 | 显示全部楼层
  1. //Socket连接进程(加入状态机实现Socket长连接和断线重连)(PS: 此代码对NetAssist.exe在WIN7下无效)
  2.     class Client_ConnectThread extends Thread {
  3.         Message msg = new Message();
  4.         @Override
  5.         public void run() {
  6.             while(true){
  7.                 //状态0: 初始化
  8.                 if(socket_state == 0){
  9.                     socket_state = 1;
  10.                     socket_connect_flag = false;

  11.                     Log.i("TcpClient", "Init");
  12.                 }
  13.                 //状态1: 连接服务器
  14.                 else if(socket_state == 1){
  15.                     try {
  16.                         //实例化对象并连接到服务器
  17.                         clientSocket = new Socket("192.168.1.112", 8888);
  18.                         //clientSocket.setSoTimeout(1000);
  19.                         socket_state = 2;
  20.                         Log.i("TcpClient", "Connect");
  21.                     } catch (UnknownHostException e1) {
  22.                         socket_state = 0;
  23.                         Log.i("TcpClient", "UnknownHost");
  24.                         e1.printStackTrace();
  25.                     } catch (IOException e1) {
  26.                         socket_state = 0;
  27.                         Log.i("TcpClient", "IOException");
  28.                         e1.printStackTrace();
  29.                     }
  30.                 }
  31.                 //状态2: 检测是否连接上, 如果连接上, 开启接收线程
  32.                 else if(socket_state == 2){
  33.                     if (clientSocket.isConnected()) {
  34.                         socket_connect_flag = true;
  35.                         socket_state = 3;

  36.                         msg.what = 1;
  37.                         msgHandler.sendMessage(msg);

  38.                         //开启接收线程
  39.                         mReceiveThread = new ReceiveThread(clientSocket);
  40.                         mReceiveThread.start();
  41.                     }
  42.                     else{
  43.                         socket_connect_flag = false;
  44.                         socket_state = 0;

  45.                         msg.what = 2;
  46.                         msgHandler.sendMessage(msg);
  47.                     }
  48.                 }
  49.                 //状态3: 发送心跳报文, 同时挂起线程
  50.                 else if(socket_state == 3){
  51.                     try {
  52.                         clientSocket.sendUrgentData(0);
  53.                         socket_state = 3;
  54.                         Log.i("TcpClient", "sendUrgentData");

  55.                         //挂起线程, 休眠10s
  56.                         try {
  57.                             Thread.sleep(10000);
  58.                         } catch (InterruptedException e1)
  59.                         {
  60.                             e1.printStackTrace();
  61.                         }
  62.                     } catch (IOException e) {
  63.                         e.printStackTrace();

  64.                         socket_state = 4;
  65.                         Log.i("TcpClient", "sendUrgentData error");

  66.                         //挂起线程, 休眠1ms
  67.                         try {
  68.                             Thread.sleep(1);
  69.                         } catch (InterruptedException e1)
  70.                         {
  71.                             e1.printStackTrace();
  72.                         }
  73.                     }
  74.                 }
  75.                 //状态4: 发送心跳报文有异常, 跳转到状态0, 重新连接
  76.                 else if(socket_state == 4){
  77.                     socket_state = 0;
  78.                     try {
  79.                         clientSocket.close();
  80.                     } catch (UnknownHostException e1) {
  81.                         e1.printStackTrace();
  82.                     } catch (IOException e1) {
  83.                         e1.printStackTrace();
  84.                     }
  85.                 }
  86.             }
  87.         }
复制代码


发心跳报文, 抛出异常就重连
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-9-27 06:22

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表