源码阅读:理解反应器模式在javaNIO中的实现-总结

经过前面的分析,大概理解了NIO的实现原理,接下来代码实现一下:
参考:

https://blog.csdn.net/billluffy/article/details/78036998
http://www.360doc.com/content/12/0902/17/495229_233773276.shtml
https://www.cnblogs.com/caca/archive/2012/03/06/3585295.html
https://www.cnblogs.com/kooker/p/9559040.html

水平不行,光看源码还是没法全部了解透。
下边是参考了上面引用地址的代码

客户端:

package netty;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
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;

/**
 * @Description:
 * @author:xuyaqi
 * @date:2018年6月6日
 */
public class Client implements Runnable {
    private int i = -1;

    public Client() {
    }

    public Client(int i) {
        this.i = i;
    }

    public static void main(String[] args) throws UnsupportedEncodingException {

        for (int i = 0; i < 1; i++) {
            new Thread(new Client(i)).start();

        }

    }

    @Override
    public void run() {
        startClient(i);
    }

    public void startClient(int i) {
        SocketChannel socketChannel = null;
        Selector selector = null;

        ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);

        try {
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 1234));

            selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_READ);
            Thread thread = new Thread(new clientHandler(selector));
            thread.start();
            String info = "客户端" + i + ":" + Math.random() * 1000;
            if (socketChannel.finishConnect()) {
                System.out.println("-------------------------------------------------------------");
                writeBuffer.clear();
                writeBuffer.put(info.getBytes("utf-8"));
                writeBuffer.flip();

                while (writeBuffer.hasRemaining()) {
                    socketChannel.write(writeBuffer);
                }
            }

//
//            while (true) {
//                if (socketChannel.finishConnect()) {
//                    String info = "客户端" + i + ":" + Math.random() * 1000;
                    while (true) {
//                    System.out.println("-------------------------------------------------------------");
//                    writeBuffer.clear();
//                    writeBuffer.put(info.getBytes("utf-8"));
//                    writeBuffer.flip();
//
//                    while (writeBuffer.hasRemaining()) {
//                        socketChannel.write(writeBuffer);
//                    }
//
//                    int bytesRead = socketChannel.read(readBuffer);
//                    if (bytesRead > 0) {
//                        readBuffer.flip();
//                        byte[] bytes = new byte[bytesRead];
//                        readBuffer.get(bytes, 0, bytesRead);
//                        String str = new String(bytes);
//                        System.out.println(str);
//                        readBuffer.clear();
//
//                    }
                        Thread.sleep(2000);
                    Thread.sleep(Integer.MAX_VALUE);
                    }
//                    break;
//                }
//            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //                if (socketChannel != null) {
//                    socketChannel.close();
//                    System.out.println("关闭socketChannel");
//                }
        }

    }

    public void hook() {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
            }
        }));
    }



}

测试发现,这个handler必须单独放,不能放client类里面。

package netty;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**

  • @author toryxu

  • @version 1.0

  • @date 2020/3/31 1:19 上午
    */
    class clientHandler implements Runnable {

    private Selector selector;

    ByteBuffer readBuffer = ByteBuffer.allocate(1024);

    public clientHandler(Selector selector) {
    this.selector = selector;
    }

    @Override
    public void run() {
    while (true) {
    try {
    if (selector.select() > 0) {
    Iterator iterator = selector.selectedKeys().iterator();
    while (iterator.hasNext()) {
    SelectionKey key = (SelectionKey) iterator.next();
    if (key.isReadable()) {
    int bytesRead = 0;
    try {
    bytesRead = ((SocketChannel) key.channel()).read(readBuffer);
    } catch (IOException e) {
    e.printStackTrace();
    }
    if (bytesRead > 0) {
    readBuffer.flip();
    byte[] bytes = new byte[bytesRead];
    readBuffer.get(bytes, 0, bytesRead);
    String str = new String(bytes);
    System.out.println(str);
    readBuffer.clear();
    }
    }
    iterator.remove();
    }
    }
    } catch (IOException e) {
    e.printStackTrace();
    }

     }
    

    }
    }


服务端

package netty;

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;

public class Server {
    private static final int BUF_SIZE = 1024;
    private static final int PORT = 1234;

    private ServerSocketChannel servSocketChannel = null;
    private Selector selector = null;

    public static void main(String[] args) {
        new Server().startServer();

    }

    public void startServer() {
        try {
            servSocketChannel = ServerSocketChannel.open();
            // 设置为非阻塞
            servSocketChannel.configureBlocking(false);
            // 绑定端口
            servSocketChannel.socket().bind(new InetSocketAddress(PORT));
            selector = Selector.open();
            // 注册监听事件
            servSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            listen();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void listen() {
        while (true) {
            try {
                //
                selector.select();
                Iterator<SelectionKey> iter = selector.selectedKeys().iterator();

                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                    if (key.isValid() && key.isAcceptable()) {
                        System.out.println("handleAccept");
                        handleAccept(key);
                    }
                    if (key.isValid() && key.isReadable()) {
                        System.out.println("handleRead");
                        handleRead(key);
                    }
                    if (key.isValid() && key.isWritable()) {
                        System.out.println("handleWrite");
                        handleWrite(key);
                    }
                    if (key.isValid() && key.isConnectable()) {
                        System.out.println("isConnectable = true");
                    }
                    //
                    iter.remove();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static void handleAccept(SelectionKey key) throws IOException {
        ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
        SocketChannel sc = ssChannel.accept();
        sc.configureBlocking(false);
        sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocateDirect(BUF_SIZE));
    }

    public static void handleRead(SelectionKey key) throws IOException {
        SocketChannel sc = (SocketChannel) key.channel();
        try {
            ByteBuffer buf = (ByteBuffer) key.attachment();

            ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
            int bytesRead = sc.read(buf);
            if (bytesRead > 0) {
                buf.flip();
                byte[] bytes = new byte[bytesRead];
                buf.get(bytes, 0, bytesRead);
                String str = new String(bytes);
                System.out.println(str);
                buf.clear();

                writeBuffer.clear();
                writeBuffer.put(bytes);
                writeBuffer.flip();
                sc.write(writeBuffer);

//                writeBuffer.put(bytes);
//                writeBuffer.flip();
//                while (writeBuffer.hasRemaining()) {
//                    sc.write(writeBuffer);
//                }
//                writeBuffer.compact();

            } else {
                //关闭客户端,服务端会发生一个read事件,并且在read的时候抛出异常,来表示关闭
                //并把socket channel关闭
                System.out.println("关闭的连接");
                key.cancel();
                sc.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
            key.cancel();
            sc.close();
        }

    }

    public static void handleWrite(SelectionKey key) throws IOException {
        ByteBuffer buf = (ByteBuffer) key.attachment();
        buf.put("客户端返回".getBytes());
        buf.flip();
        SocketChannel sc = (SocketChannel) key.channel();
        while (buf.hasRemaining()) {
            sc.write(buf);
        }
        buf.compact();
    }

}

逻辑:

服务端将serversocketchannel注册到selector,通过循环select()方法监听就绪的操作,并执行相关操作。

客户端建立连接,并在连接成功时进行写操作(判断连接成功的标志为finishConnect()返回true)。同时客户端也可以监听读操作,获得服务端返回的信息。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值