通过SocketChannel 和 ServerSocketChannel 写一个阻塞的网络IO操作

服务器

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

public class SelectorServiceDemo {

    public static void main(String[] args) throws Exception {
        int port = 8000;

        // 通过open()方法找到Selector
        Selector selector = Selector.open();

        // 打开服务器的通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 服务器配置为非阻塞
        serverSocketChannel.configureBlocking(false);
        ServerSocket serverSocket = serverSocketChannel.socket();
        InetSocketAddress address = new InetSocketAddress(port);

        // 进行服务的绑定
        serverSocket.bind(address);

        // 注册到selector,等待连接
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器运行,端口:" + port);

        // 数据缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        while (true) {
            if ((selector.select()) > 0) {

                // 选择一组键,并且相应的通道已经准备就绪
                // 取出全部生成的key
                Set selectedKeys = selector.selectedKeys();
                Iterator iter = selectedKeys.iterator();

                while (iter.hasNext()) {

                    SelectionKey key = iter.next();
                    if (key.isAcceptable()) {
                        acceptable(key, byteBuffer, selector);

                    } else if (key.isReadable() && key.isValid()) {
                        readable(selector, byteBuffer, key);

                    } else if (key.isWritable() && key.isValid()) {
                        writable(selector, byteBuffer, key);
                    }
                }

                // 清除全部的key
                selectedKeys.clear();
            }
        }
    }

    public static void writable(Selector selector, ByteBuffer byteBuffer, SelectionKey key)
            throws IOException, ClosedChannelException {
        SocketChannel client = (SocketChannel) key.channel();
        byteBuffer.clear();

        // 向缓冲区中设置内容
        byteBuffer.put(("欢迎学习NIO教程").getBytes());
        byteBuffer.flip();

        // 输出内容
        client.write(byteBuffer);
        client.register(selector, SelectionKey.OP_READ);
    }

    public static void readable(Selector selector, ByteBuffer byteBuffer, SelectionKey key)
            throws IOException, ClosedChannelException {
        SocketChannel client = (SocketChannel) key.channel();
        byteBuffer.clear();

        // 读取内容到缓冲区中
        int readSize = client.read(byteBuffer);
        if (readSize > 0) {
            System.out.println("服务器端接受客户端数据:" + new String(byteBuffer.array(), 0, readSize));
            client.register(selector, SelectionKey.OP_WRITE);
        }
    }

    public static void acceptable(SelectionKey key, ByteBuffer byteBuffer, Selector selector) throws IOException {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();

        // 接收新连接 和BIO写法类是都是accept
        SocketChannel client = server.accept();
        // 配置为非阻塞
        client.configureBlocking(false);
        byteBuffer.clear();

        // 向缓冲区中设置内容
        byteBuffer.put(("当前的时间为:" + new Date()).getBytes());
        byteBuffer.flip();
        // 输出内容
        client.write(byteBuffer);
        client.register(selector, SelectionKey.OP_READ);
    }
}

结果

![图一.png](https://upload-images.jianshu.io/upload_images/25693962-5ca5a931b4852ff5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

客户端

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

public class SelectorClientDemo {

    public static void main(String[] args) throws Exception {
        // 打开socket通道
        SocketChannel socketChannel = SocketChannel.open();

        // 设置为非阻塞方式
        socketChannel.configureBlocking(false);
        // 通过open()方法找到
        Selector selector = Selector.open();

        // 注册连接服务端socket动作
        socketChannel.register(selector, SelectionKey.OP_CONNECT);

        // 连接
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 8000));

        /* 数据缓冲区 */
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        while (true) {
            if ((selector.select()) > 0) {
                // 选择一组键,并且相应的通道已经准备就绪
                Set selectedKeys = selector.selectedKeys();// 取出全部生成的key
                Iterator iter = selectedKeys.iterator();
                while (iter.hasNext()) {
                    SelectionKey key = iter.next(); // 取出每一个key
                    if (key.isConnectable()) {
                        connection(selector, byteBuffer, key);
                    } else if (key.isReadable() && key.isValid()) {
                        readable(selector, byteBuffer, key);
                    } else if (key.isWritable() && key.isValid()) {
                        writable(selector, byteBuffer, key);
                    }
                }
                selectedKeys.clear(); // 清楚全部的key
            }
        }
    }

    public static void writable(Selector selector, ByteBuffer byteBuffer, SelectionKey key)
            throws IOException, ClosedChannelException {
        SocketChannel client = (SocketChannel) key.channel();
        byteBuffer.clear();

        // 向缓冲区中设置内容
        byteBuffer.put(("学习NIO!").getBytes());
        byteBuffer.flip();
        // 输出内容
        client.write(byteBuffer);
        client.register(selector, SelectionKey.OP_READ);
    }

    public static void readable(Selector selector, ByteBuffer byteBuffer, SelectionKey key)
            throws IOException, ClosedChannelException {
        SocketChannel client = (SocketChannel) key.channel();
        byteBuffer.clear();

        // 读取内容到缓冲区中
        int readSize = client.read(byteBuffer);
        if (readSize > 0) {
            System.out.println("客户端接受服务器端数据:" + new String(byteBuffer.array(), 0, readSize));
            client.register(selector, SelectionKey.OP_WRITE);
        }
    }

    public static void connection(Selector selector, ByteBuffer byteBuffer, SelectionKey key)
            throws IOException, ClosedChannelException {
        SocketChannel client = (SocketChannel) key.channel();
        if (client.isConnectionPending()) {
            client.finishConnect();
            byteBuffer.clear();

            // 向缓冲区中设置内容
            byteBuffer.put(("isConnect,当前的时间为:" + new Date()).getBytes());
            byteBuffer.flip();
            // 输出内容
            client.write(byteBuffer);
        }
        client.register(selector, SelectionKey.OP_READ);
    }
}  
结果
图二.png

你可能感兴趣的:(通过SocketChannel 和 ServerSocketChannel 写一个阻塞的网络IO操作)