NIO简单的实例

上篇文章是关于BIO的实例,现在知道BIO的缺点就是在不考虑多线程的情况下,无法实现并发,主要原因是有两个阻塞状态:1、服务器阻塞等待客户端的连接;2、服务器阻塞等待客户端向socket中发送消息。因此一个BIO的连接通常情况下会对CPU资源造成很大的浪费。
针对BIO的缺点,java引进了NIO(Noblocking IO)即非阻塞IO。
首先,需要了解几个重要的概念:
ServerSocketChannel:与BIO中的ServerSocket意义是一样的,都是用来监听客户端的连接,只不过多了非阻塞状态的配置
ByteBuffer:NIO专有的一个内存空间。

具体NIO服务端实例代码如下(注释中有详细介绍):

public class NioServer {

    //用来存储服务端接受到的socket
    private static List<SocketChannel> socketChannels = new ArrayList<>();
    //nio数据缓冲区
    private  static ByteBuffer byteBuffer = null;

    public static void main(String[] args) {
        try {
            ServerSocketChannel socketChannel = ServerSocketChannel.open();
            socketChannel.bind(new InetSocketAddress(8080));
            //设置非阻塞,即使没有连接,线程可以继续走下去
            socketChannel.configureBlocking(false);

            while (true) {
                //进入循环等待连接
                System.out.println("wait...conn...");
                //由于设置了非阻塞,即使没有连接也会继续执行下去(BIO当没有连接时会阻塞在这)
                SocketChannel socket = socketChannel.accept();
                if (socket == null) {
                    Thread.sleep(2000);
                    System.out.println("no...conn...");
                    //循环socketChannels,如果不为空读取消息并打印
                    for (SocketChannel clientSocket : socketChannels) {
                        byteBuffer = ByteBuffer.allocate(1024);
                        //当客户端发送消息时循环读取消息
                        int read = clientSocket.read(byteBuffer);
                        if (read > 0) {
                            byteBuffer.flip();//ByteBuffer固定写法,这里就不解释了
                            System.out.println(Charset.forName("utf-8").decode(byteBuffer));
                        }
                    }
                } else {
                    System.out.println("conn...success...");
                    //当有客户端的连接时,并将此socket设置非阻塞
                    socket.configureBlocking(false);
                    //将收到的socket添加到socketChannels中
                    socketChannels.add(socket);
                    for (SocketChannel clientSocket1 : socketChannels) {
                        byteBuffer = ByteBuffer.allocate(1024);
                        byteBuffer.flip();//ByteBuffer固定写法,这里就不解释了
                        //当客户端发送消息时循环读取消息
                        int read = clientSocket1.read(byteBuffer);
                        if (read > 0) {
                            byteBuffer.flip();
                            System.out.println(Charset.forName("utf-8").decode(byteBuffer));
                        }
                    }
                }
            }

        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

接下来是客户端的代码,跟BIO相同,此时可以多个客户端同时连接,无阻塞状态:
客户端1:

public class NioClient1 {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket();
        socket.connect(new InetSocketAddress("127.0.0.1", 8080));
        Scanner sc = new Scanner(System.in);
        while (true) {
            String msg = sc.next();
            socket.getOutputStream().write(msg.getBytes());
        }
    }
}

客户端2:

public class NioClient {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket();
        socket.connect(new InetSocketAddress("127.0.0.1", 8080));
        Scanner sc = new Scanner(System.in);
        while (true) {
            String msg = sc.next();
            socket.getOutputStream().write(msg.getBytes());
        }
    }
}

测试:
启动服务端:
可见服务端一直会打印等待连接并且此时没有连接:在这里插入图片描述
分别启动NioClient和NioClient1:
此时有两个客户端连接上,并未发生阻塞状态:在这里插入图片描述
两个客户端发送消息:
在这里插入图片描述
在这里插入图片描述
服务端收到并打印结果:
在这里插入图片描述
补充:
服务端的代码可以优化下:

public class NioServer {

    //用来存储服务端接受到的socket
    private static List<SocketChannel> socketChannels = new ArrayList<>();
    //nio数据缓冲区
    private  static ByteBuffer byteBuffer = null;

    public static void main(String[] args) {
        try {
            ServerSocketChannel socketChannel = ServerSocketChannel.open();
            socketChannel.bind(new InetSocketAddress(8080));
            //设置非阻塞,即使没有连接,线程可以继续走下去
            socketChannel.configureBlocking(false);

            while (true) {
                Thread.sleep(2000);
                for (SocketChannel socketClient : socketChannels) {
                    byteBuffer = ByteBuffer.allocate(1024);
                    System.out.println("start...read...");
                    int read = socketClient.read(byteBuffer);
                    if (read > 0) {
                        byteBuffer.flip();
                        System.out.println(Charset.forName("utf-8").decode(byteBuffer));
                    }
                }
                SocketChannel socket = socketChannel.accept();
                if (socket != null) {
                    System.out.println("conn...success...");
                    //接受到客户端的socket并将其设置为非阻塞
                    socket.configureBlocking(false);
                    socketChannels.add(socket);
                    System.out.println("socketChannels.size = " + socketChannels.size());
                }
                else {
                    System.out.println("no...conn...");
                }
            }

        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值