天天看点

非阻塞IO:NIO 服务端与客户端 基于Socket的实例

BIO:Non-Block Input Output 非阻塞式的输入和输出,面向缓冲区的。示例代码如下:

1、服务端Server

package com.example.nio.server;

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 {
    private static int port = 8080;
    private static Selector selector;
    private static ByteBuffer buffer = ByteBuffer.allocate(1024);

    static{
        try {
            //获取channel通道
            ServerSocketChannel server = ServerSocketChannel.open();
            //设置为非阻塞
            server.configureBlocking(false);
            //创建连接
            InetSocketAddress address = new InetSocketAddress(port);
            server.bind(address);
            //获取选择器,用于轮询
            selector = Selector.open();
            //使用给定的选择器注册此通道
            server.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("BioServer 已经启动,监听端口是:"+port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start (){
        try {
            //开始进行轮询
            while(true){
                //检查其相应的通道有没有已准备好进行I/O
                int count =  selector.select();
                if(count == 0){
                    continue;
                }
                //获取轮询的key,并逐个对其进行处理
                Set<SelectionKey>  keys = selector.selectedKeys();
                Iterator<SelectionKey> i = keys.iterator();
                while(i.hasNext()){
                    SelectionKey key = i.next();
                    //对每一个key进行处理
                    process(key);
                    i.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void process(SelectionKey key) throws IOException {
        //读写数据
        if(key.isAcceptable()){
            ServerSocketChannel setver = (ServerSocketChannel)key.channel();
            SocketChannel client = setver.accept();
            client.configureBlocking(false);
            client.register(this.selector,SelectionKey.OP_READ);
        }else if(key.isReadable()){
            SocketChannel client = (SocketChannel)key.channel();
            int len = client.read(this.buffer);
            if(len > 0){
                buffer.flip();
                String message = new String(buffer.array(),0,len);
                client.register(selector,SelectionKey.OP_WRITE, message);
            }
            buffer.clear();
        }else if(key.isWritable()){
            SocketChannel client = (SocketChannel)key.channel();
            String message = (String)key.attachment();
            System.out.println("服务端接收到的信息为:"+ message);
            client.write(ByteBuffer.wrap(("Clint Say:"+ message).getBytes()));
            client.close();
        }
    }

    public static void main(String[] args) {
        //NIO代码
        new NioServer().start();
    }
}
           

2、客户端Client

package com.example.nio.client;

import java.io.*;
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.Scanner;
import java.util.Set;

public class NioClient {
    private static Selector selector;
    private static SocketChannel socketChannel;
    static {
        try {
            //获取channel通道
            socketChannel = SocketChannel.open();
            //设置为非阻塞
            socketChannel.configureBlocking(false);
            //建立连接
            socketChannel.connect(new InetSocketAddress("localhost",8080));
            //获取选择器,用于轮询
            selector = Selector.open();
            //使用给定的选择器注册此通道
            socketChannel.register(selector, SelectionKey.OP_READ);
            while (!socketChannel.finishConnect()){
                System.out.println("重新连接......");
            }
            System.out.println("客户端已连接到服务端......");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        //NIO
        try {
            //设置缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            new clientThread(selector, socketChannel).start();
            while(true){
                System.out.println("send:");
                Scanner scanner = new Scanner(System.in);
                String name = scanner.nextLine();
                buffer.put(name.getBytes());
                buffer.flip();
                socketChannel.write(buffer);
                buffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class clientThread extends Thread{
        private Selector selector;
        private SocketChannel socketChannel;

        public clientThread(Selector selector, SocketChannel socketChannel) {
            this.selector = selector;
            this.socketChannel = socketChannel;
        }

        public void run(){
            try {
                //读写数据
                while (true){
                    int count = selector.select();
                    if(count == 0){
                        continue;
                    }
                    //获取轮询的key,并逐个对其进行处理
                    Set<SelectionKey> keys = selector.selectedKeys();
                    Iterator<SelectionKey> i = keys.iterator();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    while(i.hasNext()){
                        SelectionKey key = i.next();
                        if(key.isValid()){
                            if(key.isReadable()){
                                SocketChannel socketChannel = (SocketChannel)key.channel();
                                socketChannel.read(byteBuffer);
                                byteBuffer.flip();
                                byte[] bytes = new byte[byteBuffer.remaining()];
                                byteBuffer.get(bytes);
                                System.out.println("读取到的信息为:"+ new String(bytes));
                                byteBuffer.clear();
                            }
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
           

最后给出运行结果截图,这个示例稍微有点bug,有兴趣的可以研究下怎么解决:

非阻塞IO:NIO 服务端与客户端 基于Socket的实例
非阻塞IO:NIO 服务端与客户端 基于Socket的实例

继续阅读