Home Tags Posts tagged with "BIO"

BIO

代码示例:

强化理解BIO、NIO、AIO相关概念,才能正确掌握Netty的使用(毕竟要知其所以然),此篇文章从网络I/O的角度分析BIO

BIO(Blocking – I/O)是同步阻塞式的IO模型,可用于磁盘IO及网络IO等场景(IO模型为磁盘IO及网络IO服务)

传统的阻塞式通信流程(BIO)

早期的Java 网络相关的API(java.net包)使用Socket(套接字)进行网络通信,不过只支持阻塞函数使用。(Socket三元组标识通信双方,形式为:IP地址+ 协议+端口)

要通过互联网通信,至少需要一对套接字:

  • 运行于服务器端的Server Socket
  • 运行于客户机端的Client Socket

Socket网络通信过程如下图所示:

Socket 网络通信过程简单来说分为4步:

  • 1.建立服务器端并监听客户端请求
  • 2.客户端请求,服务器端和客户端建立连接
  • 3.两端之间可以传递数据
  • 4.关闭资源

服务器端:

  • 1.创建 ServerSocket 对象并绑定地址(ip)和端口号(port):server.bing(new InetSocketAddress(host,port))
  • 2.通过 accept()方法监听客户端请求
  • 3.连接建立后,通过输入流读取客户端发送的请求消息
  • 4.通过输出流向客户端发送响应消息
  • 5.关闭相关资源

客户端:

  • 1.创建 Socket 对象并连接指定服务器的地址(ip)和端口号(port):
  • socket.connect(inetSocketAddress)
  • 2.连接建立后,通过输出流向服务器端发送请求信息
  • 3.通过输入流获取服务器响应的信息
  • 4.关闭相关资源

 

存在问题:资源消耗严重

很明显,上面的代码片段有一个很严重的问题:只能同时处理一个客户端的连接,如果需要管理多个客户端的话,就需要为我们请求的客户端单独创建一个线程,如下图

对应的 Java 代码可能是下面这样的:

new Thread(() -> {
   // 创建 socket 连接
}).start();

但是,这样会导致一个很严重的问题:资源浪费

我们知道线程是很宝贵的资源,如果我们为每一次连接都用一个线程处理的话,就会导致线程越来越多,最后达到了极限之后,就无法再创建线程处理请求了。处理的不好的话,甚至可能直接就宕机掉了。

很多人就会问了:那有没有改进的方法呢?

线程池虽可以改善,但终究未从根本解决问题

当然有! 比较简单并且实际的改进方法就是使用线程池。线程池还可以让线程的创建和回收成本相对较低,并且我们可以指定线程池的可创建线程的最大数量,这样就不会导致线程创建过多,机器资源被不合理消耗。

ThreadFactory threadFactory = Executors.defaultThreadFactory();
ExecutorService threadPool = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(100), threadFactory);
threadPool.execute(() -> {
     // 创建 socket 连接
 });

但是,即使你再怎么优化和改变。也改变不了它的底层仍然是同步阻塞的 BIO 模型的事实,因此无法从根本上解决问题。

为了解决上述的问题,Java 1.4 中引入了 NIO ,一种同步非阻塞的 I/O 模型。

文章链接:https://zhuanlan.zhihu.com/p/196759269

对BIO更好的理解:浅谈“阻塞同步”,“BIO、NIO、AIO” – 简书 (jianshu.com)