从实践角度重新理解BIO和NIO(上)

简介: 从实践角度重新理解BIO和NIO(上)

前言


这段时间自己在看一些Java中BIO和NIO之类的东西,看了很多博客,发现各种关于NIO的概念说的天花乱坠头头是道,可以说是非常的完整,但是整个看下来之后,自己对NIO还是一知半解的状态,所以这篇文章不会提到很多的概念,而是站在一个实践的角度,写一些我自己关于NIO的见解,站在实践过后的高度下再回去看概念,应该对概念会有一个更好的理解。



实现一个简易单线程服务器


要讲明白BIO和NIO,首先我们应该自己实现一个简易的服务器,不用太复杂,单线程即可。


为什么使用单线程作为演示


因为在单线程环境下可以很好地对比出BIO和NIO的一个区别,当然我也会演示在实际环境中BIO的所谓一个请求对应一个线程的状况。


服务端


public class Server {
    public static void main(String[] args) {
        byte[] buffer = new byte[1024];
        try {
            ServerSocket serverSocket = new ServerSocket(8080);
            System.out.println("服务器已启动并监听8080端口");
            while (true) {
                System.out.println();
                System.out.println("服务器正在等待连接...");
                Socket socket = serverSocket.accept();
                System.out.println("服务器已接收到连接请求...");
                System.out.println();
                System.out.println("服务器正在等待数据...");
                socket.getInputStream().read(buffer);
                System.out.println("服务器已经接收到数据");
                System.out.println();
                String content = new String(buffer);
                System.out.println("接收到的数据:" + content);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


客户端


public class Consumer {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1",8080);
            socket.getOutputStream().write("向服务器发数据".getBytes());
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


代码解析


我们首先创建了一个服务端类,在类中实现实例化了一个SocketServer并绑定了8080端口。之后调用accept方法来接收连接请求,并且调用read方法来接收客户端发送的数据。最后将接收到的数据打印。


完成了服务端的设计后,我们来实现一个客户端,首先实例化Socket对象,并且绑定ip为127.0.0.1(本机),端口号为8080,调用write方法向服务器发送数据。



image.png


运行结果


当我们启动服务器,但客户端还没有向服务器发起连接时,控制台结果如下:


image.png


当客户端启动并向服务器发送数据后,控制台结果如下:


image.png



结论


从上面的运行结果,首先我们至少可以看到,在服务器启动后,客户端还没有连接服务器时,服务器由于调用了accept方法,将一直阻塞,直到有客户端请求连接服务器。


对客户端功能进行扩展


在上文中,我们实现的客户端的逻辑主要是,建立Socket --> 连接服务器 --> 发送数据,我们的数据是在连接服务器之后就立即发送的,现在我们来对客户端进行一次扩展,当我们连接服务器后,不立即发送数据,而是等待控制台手动输入数据后,再发送给服务端。(服务端代码保持不变)


代码


public class Consumer {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1",8080);
            String message = null;
            Scanner sc = new Scanner(System.in);
            message = sc.next();
            socket.getOutputStream().write(message.getBytes());
            socket.close();
            sc.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


测试


image.png


当服务端启动,客户端连接服务端,但没有发送数据时,控制台结果如下:


image.png


当服务端启动,客户端连接服务端,并且发送数据时,控制台结果如下:


image.png


结论


从上文的运行结果中我们可以看到,服务器端在启动后,首先需要等待客户端的连接请求(第一次阻塞),如果没有客户端连接,服务端将一直阻塞等待,然后当客户端连接后,服务器会等待客户端发送数据(第二次阻塞),如果客户端没有发送数据,那么服务端将会一直阻塞等待客户端发送数据。


服务端从启动到收到客户端数据的这个过程,将会有两次阻塞的过程。这就是BIO的非常重要的一个特点,BIO会产生两次阻塞,第一次在等待连接时阻塞,第二次在等待数据时阻塞。


当服务端启动,客户端还没有请求连接服务器时,控制台结果如下:

相关文章
|
14天前
|
网络协议 Dubbo Java
一文搞懂NIO、AIO、BIO的核心区别(建议收藏)
本文详细解析了NIO、AIO、BIO的核心区别,NIO的三个核心概念,以及NIO在Java框架中的应用等。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
一文搞懂NIO、AIO、BIO的核心区别(建议收藏)
|
3月前
|
设计模式
Lettuce的特性和内部实现问题之Netty NIO的性能优于BIO的问题如何解决
Lettuce的特性和内部实现问题之Netty NIO的性能优于BIO的问题如何解决
|
2月前
|
Java
Netty BIO/NIO/AIO介绍
Netty BIO/NIO/AIO介绍
|
1月前
|
Java Linux 应用服务中间件
【编程进阶知识】高并发场景下Bio与Nio的比较及原理示意图
本文介绍了在Linux系统上使用Tomcat部署Java应用程序时,BIO(阻塞I/O)和NIO(非阻塞I/O)在网络编程中的实现和性能差异。BIO采用传统的线程模型,每个连接请求都会创建一个新线程进行处理,导致在高并发场景下存在严重的性能瓶颈,如阻塞等待和线程创建开销大等问题。而NIO则通过事件驱动机制,利用事件注册、事件轮询器和事件通知,实现了更高效的连接管理和数据传输,避免了阻塞和多级数据复制,显著提升了系统的并发处理能力。
62 0
|
3月前
|
缓存 Java UED
BIO、NIO、AIO有什么区别
【8月更文挑战第16天】BIO、NIO、AIO有什么区别
80 4
|
3月前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
89 2
|
4月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
165 1
|
4月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
4月前
|
Java
Java中的NIO编程详解
Java中的NIO编程详解
|
4月前
|
Java 大数据
如何在Java中进行网络编程:Socket与NIO
如何在Java中进行网络编程:Socket与NIO