文档章节

SocketChannel 异步的socket 连接

 木头板板
发布于 2017/03/31 15:45
字数 759
阅读 10
收藏 0

socketChannel 是java中用于建立异步socket连接的工具类,他和socket 非常类似。相似的 ServerSocketChannel 对应于 ServerSocket,即socket 的服务端。在java 中这两个类是实现异步socket的关键类。

    此外还有几个十分关键的工具类Selector ,顾名思义seletor 是异步socket中的一个通道选择器,我的理解中类似一个socket的map集合,凭借selector 的强大功能我们不再需要为每一个socket通道维持一个专门的线程,我们可以在一个线程里处理所有的连接。

先看看服务端的初始化

// 打开通道管理器
selector = Selector.open();
// 打开一个未绑定的服务端通道对象
serverChannel = ServerSocketChannel.open();
// 将此服务端对象绑定端口,Ip默认是本机的Ip,如果本机有多个ip,需要指定ip
serverChannel.socket().bind(new InetSocketAddress(PORT));
// 设定服务端为非阻塞方式工作
serverChannel.configureBlocking(false);

 

// 把设定好的服务端注册到通道管理器中    ,该操作会创建一个选择键
serverChannel.register(selector, SelectionKey.OP_ACCEPT, BUFFER_SIZE);

必须经过注册之后selector 通道管理器中的值才会大于零

selector的selectionKey 有四种状态,acceptable ,  connectable, readable,writable  可用isXXX判断

在线程中执行以下代码:(服务端)

while (selector.select() > 0) {             //此方法是一个阻塞操作
            //Log.e(TAG,"外层循环");
            Set<SelectionKey> selectionKeys= selector.selectedKeys();   // 获取全部的已选择键,
                                                                        //可以直接移除单不可直接添加
             Iterator<SelectionKey>    it=   selectionKeys.iterator();
               while (it.hasNext()){
               SelectionKey skey=it.next();      //对已经注册的socket的集合进行迭代
               it.remove();                       // 被移除的是集合selectionKeys中的对象不是selector的对象
                                                 //该操作用于结束内层循环   
               Boolean flag = false;
               if (skey.isAcceptable()) {                           //有新的连接请求
                  SocketChannel channel = serverChannel.accept();
                  String clientIp = getClientIp(skey,channel);         
                  channel.configureBlocking(false);                     //不阻塞
                  Log.e(TAG,"client online "+ clientIp);
                  new NSServerClientOnline(onlines, clientIp).run();    //自定义客户端上线回调   
                  try {
                     channel.register(selector, SelectionKey.OP_READ); //重新注册为可读状态 
                  } catch (Exception e) {
                     flag = true;
                     skey.cancel();
                     if (skey.channel() != null) {
                        skey.channel().close();
                     }
                  }
//

               }
               if (skey.isReadable()) {                      
                  StringBuffer message = new StringBuffer();
                  SocketChannel channel = (SocketChannel) skey.channel();
                  String clientIp = getClientIp(skey,channel);
                  ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
                  try {
                     if(channel.read(buffer)<0){
                        flag = true;
                        skey.cancel();
                        if (skey.channel() != null) {
                           skey.channel().close();
                        }
                     }
                     while (channel.read(buffer) > 0) {
                     }
                     buffer.flip();                    //此方法刷新缓存的buffer 此方法慎用他回修改selectionKey的状态
                     message.append(charse.decode(buffer));

                     if (null != message && message.length() > 0) {
                        Log.e(TAG,"服务端收到消息" + message);
                        new NSServerReceive(receives, message, clientIp).run();
                     }
                     skey.interestOps(SelectionKey.OP_READ);  //修改 读写状态
                  } catch (Exception e) { 
                     flag = true;
                     skey.cancel();
                     if (skey.channel() != null) {
                        skey.channel().close();
                     }
                  }
               }
               if (flag) {
                        new NSServerClientOffline(offLines, getClientIp(skey, null)).run();
                    }
            }
         }
         instance().start();      // 如果异常退出大循环 重启服务
      } catch (IOException e) {
         e.printStackTrace();
         Log.e(TAG," socekct server  crash");
      }

 

客户端代码类似服务端,这里提供一个客户端判断连接断开的方法,,网上找的不知道可靠不

就是当连接状态可读的时候去试读取信息

 

if(clientChannel.read(buffer)<0){
   Log.e(TAG,"socket client read buffer");
   flag = true;
   skey.cancel();
   if (skey.channel() != null) {
      skey.channel().close();
   }
   break TT;             // 读取的内容为-1 判断为连接断开
                         // 因为这是一个异步的socket 所以可以放入死循环线程中,所以基本可以立马收到断开连接的消息   
}

 

© 著作权归作者所有

共有 人打赏支持
粉丝 2
博文 32
码字总数 13492
作品 0
成都
私信 提问
Scalable IO in Java 的简单解读

final Selector selector;//ServerSocketChannel//支持异步操作,对应于java.net.ServerSocket这个类,提供了TCP协议IO接口,支持OP_ACCEPT操作。final ServerSocketChannel serverSocket; R......

cafe
2013/07/25
0
0
Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解。 下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端。 代码的所有说明...

hgqxjj
2017/11/30
0
0
09. Java NIO SocketChannel 套接字通道

在Java NIO体系中,SocketChannel是用于TCP网络连接的套接字接口,相当于Java网络编程中的Socket套接字接口。创建SocketChannel主要有两种方式,如下: 打开一个SocketChannel并连接网络上的...

逝去的回忆
2016/11/19
21
0
高性能Server---Reactor模型

在这个充斥着云的时代,我们使用的软件可以说99%都是C/S架构的! 你发邮件用的Outlook,Foxmail等 你看视频用的优酷,土豆等 你写文档用的Office365,googleDoc,Evernote等 你浏览网页用的IE,...

tantexian
2017/11/07
0
0
NIO socket 的简单连接池

在最近的项目中,需要写一个socket 与 底层服务器通信的模块。在设计中,请求对象被封装 xxxRequest,消息返回被封装为 xxxResponse. 由于socket的编程开发经验少,一开始我使用了短连接的方式...

墙头草
2011/05/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Vue.js开发环境搭建说明(mac)

vue开发环境搭建(mac) 投影放大:cmd + + 安装Node 下载Node 官网下载 https://nodejs.org/en/download/ 安装Node 双击安装包,选择安装目录,比如: /usr/local/bin 安装成功后最好记录一...

Danni3
7分钟前
0
0
Qt编写自定义控件3-速度仪表盘

前言 速度仪表盘,写作之初的本意是用来展示当前测试的网速用的,三色圆环+数码管显示当前速度,Qt自带了数码管控件QLCDNumber,直接集成即可,同时还带有动画功能,其实也可以用在汽车+工业...

飞扬青云
12分钟前
0
0
【论文阅读】Image Super-Resolution via Deep Recursive Residual Network

题目:通过深度递归残差网络实现图像的超分辨率 摘要: 近年来,基于卷积神经网络的模型在单张图像的超分辨率上已经取得了巨大的成功。由于深度网络的强大,这些CNN模型学习了从低分辨率输入...

云烟成雨forever
15分钟前
0
0
为什么强烈建议大家使用枚举来实现单例

关于单例模式,我的博客中有很多文章介绍过。作为23种设计模式中最为常用的设计模式,单例模式并没有想象的那么简单。因为在设计单例的时候要考虑很多问题,比如线程安全问题、序列化对单例的...

群星纪元
33分钟前
10
0
Confluence 6 超过当前许可证期限进行升级

这个页面将会对你在进行 Confluence 升级的时候超过了当前许可证的期限进行升级的情况。 许可证警告 在升级的过程中,你将会在 Confluence 的应用程序日志(log file)中看到类似下面的错误提...

honeymoose
46分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部