NIO从入门到精通

java NIO

nio三剑客

NIO三剑客

 

buffer三剑客

 

多路复用的范式

server

package com.deppyu.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;

/**
 * @author deppyu
 * @date 2019-08-12 12:46
 */
public class NioServerDemo {

    volatile static Map<Integer , String> keyAndName = new HashMap<>(4);

    static{
        keyAndName.put(SelectionKey.OP_CONNECT , "OP_CONNECT");
        keyAndName.put(SelectionKey.OP_ACCEPT , "OP_ACCEPT");
        keyAndName.put(SelectionKey.OP_READ , "OP_READ");
        keyAndName.put(SelectionKey.OP_WRITE , "OP_WRITE");
        System.out.println(keyAndName);
    }

    public volatile static Map<String,SocketChannel> connStore = new HashMap<String, SocketChannel>(16);

    public static List<SocketAddress> getSocketAddressList(){
        List<SocketAddress> socketAddresses = new ArrayList<>(4);
        socketAddresses.add(new InetSocketAddress(5566));
//        socketAddresses.add(new InetSocketAddress(7788));
//        socketAddresses.add(new InetSocketAddress(1234));
        return socketAddresses;
    }

    public static String getOpeNameById(Integer key){
        return keyAndName.get(key);
    }

    public static void main(String[] args) throws IOException {
        List<SocketAddress> socketAddresses = getSocketAddressList();

        Selector selector = Selector.open();

        for(SocketAddress socketAddress : socketAddresses){
//            这个是等待可用请求的channel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            ServerSocket serverSocket = serverSocketChannel.socket();
            serverSocket.bind(socketAddress);
//            accept()函数功能是,从处于 established 状态的连接队列头部取出一个已经完成的连接,如果这个队列没有已经完成的连接,accept()函数就会阻塞,直到取出队列中已完成的用户连接为止。
//            serverSocketChannel关注的是连接事件
            serverSocketChannel.register(selector , SelectionKey.OP_ACCEPT);
        }

        while(true){
            System.out.println("阻塞等待新的事件到来->  ...");
            selector.select();

            Set<SelectionKey> selectionKeySet = selector.selectedKeys();

            //同一个端口的连接事件 即便多次 都对应同一个selectKey
            System.out.println("selector中的事件数量=" + selectionKeySet.size());
            for(SelectionKey selectionKey : selectionKeySet){
                System.out.println("行为=" + getOpeNameById(selectionKey.interestOps()) + selectionKey.toString());
            }

            Iterator<SelectionKey> iterator = selectionKeySet.iterator();
            while (iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                try{
                    if(selectionKey.isAcceptable()){
                        SelectableChannel selectableChannel = selectionKey.channel();
                        ServerSocketChannel serverSocketChannel = (ServerSocketChannel)selectableChannel;

                        //阻塞的等待连接建立好,这里的channel可以理解成是一种连接
                        SocketChannel socketChannel = serverSocketChannel.accept();

                        if(socketChannel!=null){
                            socketChannel.configureBlocking(false);
                            //此处的socketChannel关注的是读取数据事件
                            socketChannel.register(selector , SelectionKey.OP_READ);
                            String key = "user-"+UUID.randomUUID().toString();
                            System.out.println("key->" + key + " channel->[" + socketChannel + "]上线");
                            connStore.put(key , socketChannel);
                        }
                    }else if(selectionKey.isReadable()){
                        ByteBuffer byteBuffer = ByteBuffer.allocate(512);
                        while(true){
                            byteBuffer.clear();

                            SocketChannel channel = (SocketChannel)selectionKey.channel();
                            byteBuffer.put("->".getBytes());
                            int length = channel.read(byteBuffer);

                            if(length <= 0){
                                break;
                            }

                            for(Map.Entry<String,SocketChannel> entry : connStore.entrySet()){
                                byteBuffer.flip();
                                entry.getValue().write(byteBuffer);
                            }

                        }
                    }
                }finally {
                    iterator.remove();
                }

            }
        }

    }

}

 

client

package com.deppyu.nio;

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;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author deppyu
 * @date 2019-08-12 21:15
 */
public class NioClientDemo {

    static ExecutorService executorService = Executors.newSingleThreadExecutor();

    public static void main(String[] args) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.connect(new InetSocketAddress(5566));
        System.out.println("原始channel->"+socketChannel);

        Selector selector = Selector.open();
        socketChannel.register(selector , SelectionKey.OP_CONNECT);

        while(true){
            selector.select();
            Set<SelectionKey> selectionKeySet = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeySet.iterator();
            while(iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                if(selectionKey.isConnectable()){
                    SocketChannel channel = (SocketChannel)selectionKey.channel();
                    System.out.println("isConnectionPending ->" + channel.isConnectionPending());
                    if(channel.isConnectionPending()){
                        channel.finishConnect();
                    }
                    channel.register(selector , SelectionKey.OP_READ);
                    executorService.submit(new Runnable() {
                        @Override
                        public void run() {
                            ByteBuffer byteBuffer = ByteBuffer.allocate(512);
                            while(true){
                                InputStreamReader inputStreamReader = new InputStreamReader(System.in);
                                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                                try {
                                    String message = bufferedReader.readLine();
                                    byteBuffer.clear();
                                    byteBuffer.put(message.getBytes());
                                    byteBuffer.flip();
                                    channel.write(byteBuffer);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    });
                }else if(selectionKey.isReadable()){
                    SocketChannel socketChannelRead = (SocketChannel)selectionKey.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(512);
                    while(true){
                        byteBuffer.clear();
                        int length = socketChannelRead.read(byteBuffer);
                        if(length<=0){
                            break;
                        }
                        String msgReceived = new String(byteBuffer.array() , 0 , length);
                        System.out.println("收到的服务器的消息->"+msgReceived);
                    }
                }
                iterator.remove();
            }
        }

    }

}

 

netty的reactor模式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值