A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© fjl_fight 中级黑马   /  2013-5-3 16:07  /  3272 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

  在使用java.io和Socket构建网络服务时,所有的网络服务将使用阻塞式方式进行客户端连接。而使用java.nio则可以构建一个非阻塞式的网络服务
一、Selector类
  主要方法:
            打开一个选择器。通过调用系统级默认 SelectorProvider 对象的 openSelector 方法来创建新的选择器。   


              选择一组键,其相应的通道已为 I/O 操作准备就绪。此方法执行处于阻塞模式的选择操作。仅在至少选择一个通道、调用此选择器的 wakeup 方法,或者当前的线程已中断(以先到者为准)后此方法才返回。                       public abstract Set<SelectionKey> selectedKeys()                  返回此选择器的已选择键集。可从已选择键集中移除键,但是无法直接添加键。试图向该键集中添加对象会导致抛出 UnsupportedOperationException。已选择键集是非线程安全的

      在进行非阻塞网络开发需使用SelectableChannel类向Select注册,而在NIO中实现网络程序需依靠ServerSocketChannel类与SocketChannel类,它们都是SelectableChannel的子类,SelectableChannel提供了注册Selector的方法和阻塞模式。
    ServerSocketChannel 的主要方法:
public final SelectionKey register(Selector sel,int ops) throws ClosedChannelException
     向给定的选择器注册此通道,返回一个选择键。  public abstract SelectableChannel configureBlocking(boolean block)throws IOException   调整此通道的阻塞模式。如果向一个或多个选择器注册了此通道,则尝试将此通道置于阻塞模式将导致抛出 IllegalBlockingModeException。可在任意时间调用此方法。新的阻塞模式仅影响在此方法返回后发起的 I/O 操作。对于某些实现而言,这可能需要在所有挂起的 I/O 操作完成之前阻塞其他操作。
如果调用此方法的同时正在进行另一个此方法或 register 方法的调用,则在另一个操作完成前将首先阻塞该调用。
      参数block - 如果为 true,则此通道将被置于阻塞模式;如果为 false,则此通道将被置于非阻塞模式,
      返回值:此可选择通道
public static ServerSocketChannel open() throws IOException       打开服务器套接字通道。通过调用系统级默认 SelectorProvider 对象的 openServerSocketChannel 方法来创建新的通道。       新通道的套接字最初是未绑定的;可以接受连接之前,必须通过它的某个套接字的 bind 方法将其绑定到具体的地址。


public abstract ServerSocket socket()     获取与此通道关联的服务器套接字。4种Selector域(来源 JAVA API)
[size=-1]static int
OP_ACCEPT
          用于套接字接受操作的操作集位。
[size=-1]static int
OP_CONNECT
          用于套接字连接操作的操作集位。
[size=-1]static int
OP_READ
          用于读取操作的操作集位。
[size=-1]static int
OP_WRITE
          用于写入操作的操作集位。

如果要向客户端发送信息,则许通过SelectionKey类的方法判断服务器操作状态,儿想去的刻画段的连接也需要使用SelectionKey类
[size=-1]abstract  SelectableChannel
channel()
          返回为之创建此键的通道。
[size=-1] boolean
isAcceptable()
          测试此键的通道是否已准备好接受新的套接字连接。
[size=-1] boolean
isConnectable()
          测试此键的通道是否已完成其套接字连接操作。
[size=-1] boolean
isReadable()
          测试此键的通道是否已准备好进行读取。
[size=-1] boolean
isWritable()
          测试此键的通道是否已准备好进行写入。
例如:利用Selector创建一个非阻塞的服务器,此服务器向客户端返回当前时间

package com;import java.net.InetSocketAddress ;import java.net.ServerSocket ;import java.util.Set ;import java.util.Iterator ;import java.util.Date ;import java.nio.channels.ServerSocketChannel ;import java.nio.ByteBuffer ;import java.nio.channels.SocketChannel ;import java.nio.channels.Selector  ;import java.nio.channels.SelectionKey  ;public class DateServer{        public static void main(String args[]) throws Exception {                // 表示五个监听端口                int ports[] = {8000,8001,8002,8003,8005,8006} ;                 // 通过open()方法找到Selector                Selector selector = Selector.open() ;                        for(int i=0;i<ports.length;i++){                        ServerSocketChannel initSer = null ;                        // 打开服务器的通道                        initSer = ServerSocketChannel.open() ;                                // 服务器配置为非阻塞                        initSer.configureBlocking(false) ;                                ServerSocket initSock = initSer.socket() ;                        InetSocketAddress address = null ;                        // 实例化绑定地址                        address = new InetSocketAddress(ports) ;                                // 进行服务的绑定                        initSock.bind(address) ;                                // 等待连接                        initSer.register(selector,SelectionKey.OP_ACCEPT) ;                        System.out.println("服务器运行,在" + ports + "端口监听。") ;                }                // 要接收全部生成的key,并通过连接进行判断是否获取客户端的输出                int keysAdd = 0 ;                // 选择一组键,并且相应的通道已经准备就绪                while((keysAdd=selector.select())>0){                                // 取出全部生成的key                        Set<SelectionKey> selectedKeys = selector.selectedKeys() ;                        Iterator<SelectionKey> iter = selectedKeys.iterator() ;                        while(iter.hasNext()){                                // 取出每一个key                                SelectionKey key = iter.next() ;                                        if(key.isAcceptable()){                                        ServerSocketChannel server = (ServerSocketChannel)key.channel() ;                                        // 接收新连接                                        SocketChannel client = server.accept() ;                                                // 配置为非阻塞                                        client.configureBlocking(false) ;                                        ByteBuffer outBuf = ByteBuffer.allocateDirect(1024) ;                                                // 向缓冲区中设置内容                                        outBuf.put(("当前的时间为:" + new Date()).getBytes()) ;                                                outBuf.flip() ;                                        // 输出内容                                        Thread.sleep(3000);                                        client.write(outBuf) ;                                                // 关闭                                        client.close() ;                                        }                        }                        // 清楚全部的key                        selectedKeys.clear() ;                        }                        }}
然后用telnet客户端测试。



















2 个回复

倒序浏览
这技术分怎么挣啊
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马