SelectionKey,read,

SelectionKey:
- 每次一个Channel注册到一个Selector时,都会返回一个SelectionKey的实例,
- 在使用一个SelectionKey实例之前,我们可以通过isValid()来判断这个实例的合法性(有没有被其他线程取消,对应channel有没有被关闭,对应的selector有没有被关闭,等等)
- 一个SelectionKey包含有两个被操作的集,一个是interest set(决定了selector调用select()方法时对它对应Channel的哪一种操作进行测试(一共有四种可以选择)),另一个是ready set(用于标识这个key是否处于准备状态),这两个集都是通过整数来标识的
- 针对第三点中提到的“四种选择”,不是对每一个Channel都有效的,这还取决于这个Channel的类型,具体的还可以通过SelectableChannel提供的validOps()方法,来查询那些set是被当前这个Channel所支持的
- SelectionKey可以有一个attachmen(附件),这个附件作为一个对象可以携带一些其他的东西。通过attach方法可以添加这个附件
- SelectionKey是线程安全的,这意味它可以用于多并发编程之中,因为它会被某个正在操作它的Selector强制同步

常用方法分析
- public final boolean isAcceptable();//测试key对应的channel是否准备创建一个新的socket connection,如果一个key对应的channel不支持socket-accept操作,通常会返回false
- public final boolean isConnectable();//测试key对应的channel是否已经完成或者失败了socket-connection(socket建立)操作,也就是说,要让这个方法返回true,他必须满足两个条件,第一,key调用的readyOps()函数的返回值必须是true,即调用这个方法之后返回的int数字,必须是SelectionKey的Operation-set当中的一种,第二,这个key的Operation-set bit 必须是OP_CONNECTION(对应的是一个数字),
- public final boolean isAcceptable();//测试这个key所对应的channel是否已经准备好来建立一个新的socket连接,这个方法需要返回true,也需要满足两个条件,,第一,key调用的readyOps()函数的返回值必须是true,即调用这个方法之后返回的int数字,必须是SelectionKey的Operation-set当中的一种,第二,这个key的Operation-set bit 必须是OP_ACCEPT(对应的是一个数字),
- 关乎上面两个方法的两个条件,第一个条件代表的是这个key对应的channel准备好了,后一个条件是在准备好了的基础之上,满足特定的某个操作。
- 类似的还有 public final boolean isReadable(),public final boolean isWritable()

下面给出测试代码:


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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NIOServer {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String host="127.0.0.1";
        int port = 8090;
        new Thread(new NIOServerHandler(host,port)).start();
    }

}


 class NIOServerHandler implements Runnable {

    private ServerSocketChannel ssc;
    private Selector selector;
    public NIOServerHandler(String host,int port) {
        // TODO Auto-generated constructor stub
        try {
            ssc=ServerSocketChannel.open();
            ssc.socket().bind(new InetSocketAddress(host,port));
            ssc.configureBlocking(false);
            selector=Selector.open();
            ssc.register(selector, SelectionKey.OP_ACCEPT);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            try {
                selector.select(3000);
                Set<SelectionKey> sk=selector.selectedKeys();
                Iterator<SelectionKey> it=sk.iterator();

                while(it.hasNext()){
                    SelectionKey key=it.next();
                    it.remove();
                    handlerKey(key);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    private void handlerKey(SelectionKey key) throws IOException {
        // TODO Auto-generated method stub
        if(key.isValid()){
            //判断是是否有接入请求,
            if(key.isAcceptable()){
                SocketChannel sc=((ServerSocketChannel)key.channel()).accept();
                sc.configureBlocking(false);
                sc.register(selector, SelectionKey.OP_READ);

            }
            //判断是否有等待读取的消息
            if(key.isReadable()){
                ByteBuffer readBuffer=ByteBuffer.allocate(1024);
                ((SocketChannel)key.channel()).read(readBuffer);
                readBuffer.flip();
                byte[] bytes=new byte[readBuffer.remaining()];
                readBuffer.get(bytes);
                System.out.println("收到新消息"+new String(bytes,"UTF-8"));

                //返回一个结果
                byte[] writeBytes ="我收到了一条消息".getBytes("UTF-8");
                ByteBuffer writeBuffer = ByteBuffer.allocate(writeBytes.length);
                writeBuffer.put(writeBytes);
                writeBuffer.flip();
                ((SocketChannel)key.channel()).write(writeBuffer);
            }
        }
    }

}
package nettyJava.Chapter2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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.util.Iterator;
import java.util.Set;

public class NIOClient {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String host="127.0.0.1";
        int port = 8090;
        new Thread(new NIOClientHandler(host,port)).start();
    }

}


class NIOClientHandler implements Runnable{

    private SocketChannel sc;
    private String host;
    int port;
    private Selector selector;

    public NIOClientHandler(String host,int port) {
        // TODO Auto-generated constructor stub
        this.host=host;
        this.port=port;
        try {
            sc=SocketChannel.open();
            sc.configureBlocking(false);
            selector =Selector.open();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            socketChannelConnect();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        while(true){
            try {
                selector.select(6000);
                //获取被选择key,并且以此检查并操作每个key;
                Set<SelectionKey> selectedKey=selector.selectedKeys();
                Iterator<SelectionKey> it=selectedKey.iterator();
                while(it.hasNext()){
                    SelectionKey key=it.next();
                    it.remove();
                    handlerKey(key);
                }
            } catch (IOException e) {

                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }


    private void handlerKey(SelectionKey key) throws IOException{
        if(key.isValid()){
            SocketChannel socket=(SocketChannel) key.channel();
            //判断socket是否处于连接成功,如果成功则需要注册
            if(key.isConnectable()){

                if(socket.finishConnect()){//表明连接已经建立
                    /*
                     * Finishes the process of connecting a socket channel.
                     * true if, and only if, this channel's socket is now connected
                     */

                    socket.register(selector, SelectionKey.OP_READ);//注册这个channel,并且说明感兴趣的方面
                }else{
                    System.exit(1);
                }
            }

            //判断是否可读

            if(key.isReadable()){
                doRead(key);
                doWrite(socket);
            }
        }
    }

    private void doRead(SelectionKey key) throws IOException{
        System.out.println("从server输入的数据");
        ByteBuffer readBuffer=ByteBuffer.allocate(1024);
        SocketChannel sc=(SocketChannel) key.channel();
        int readSize=sc.read(readBuffer);
        readBuffer.flip();
        if(readSize>0){
            byte[] bytes=new byte[readBuffer.remaining()];
            readBuffer.get(bytes);
            System.out.println(new String(bytes,"UTF-8"));
        }
    }

    private void socketChannelConnect() throws IOException{
        //将这个sc连接到server,并且注册到监听器
        sc.connect(new InetSocketAddress(host,port));
        if(sc.finishConnect()){
            sc.register(selector, SelectionKey.OP_READ);
            doWrite(sc);
        }
        else
            sc.register(selector, SelectionKey.OP_CONNECT);
    }

    private void doWrite(SocketChannel socket) throws IOException{
        //byte[] bytes="this is a test".getBytes("UTF-8");

        System.out.println("向server输出数据:回车后ok结束");
        BufferedReader consoleIn=new BufferedReader(new InputStreamReader(System.in));
        String sendMessage="";
        while(true){
            String temp=consoleIn.readLine();
            if(temp.equals("ok"))break;
            sendMessage+=temp+"\n";
        }
        byte[] sendBytes=sendMessage.getBytes("UTF-8");
        ByteBuffer writeBuffer=ByteBuffer.allocate(sendBytes.length);
        writeBuffer.put(sendBytes);
        writeBuffer.flip();
        socket.write(writeBuffer);
    }

}

服务器端的每一个和客户端通信的socket,都是通过serverSocket的accept方法来创建的,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值