Java 输入与输出之 NIO【非阻塞式IO】【NIO网络编程】探索之【二】

ops/2024/11/13 9:11:13/

上一篇博客我们介绍了NIO的核心原理、FileChannel和Buffer, 对Buffer的用法有了清晰的了解。上篇博客:
Java 输入与输出之 NIO【非阻塞式IO】【NIO核心原理】探索之【一】
本篇博客我们将继续来探索NIO,介绍如何使用SocketChannel和ServerSocketChannel来实现TCP协议的非阻塞套接字(Socket)网络通信程序编程。NIO的强大功能部分来自于Channel的非阻塞特性,套接字的某些操作可能会无限期地阻塞。例如,对accept()方法的调用可能会因为等待一个客户端连接而阻塞;对read()方法的调用可能会因为没有数据可读而阻塞,直到连接的另一端传来新的数据。总的来说,创建/接收连接或读写数据等I/O调用,都可能无限期地阻塞等待。
NIO的Channel抽象的一个重要特征就是可以通过配置它的阻塞行为,以实现非阻塞式的信道。
下面这行代码设置了通道的非阻塞模式:
channel.configureBlocking(false)

在非阻塞式信道上调用一个方法总是会立即返回。这种调用的返回值指示了所请求的操作完成的程度。例如,在一个非阻塞式ServerSocketChannel上调用accept()方法,如果有连接请求来了,则返回客户端SocketChannel,否则返回null。

三、利用NIO编写网络通信程序(Selector的核心应用)

网络通信相关的三大核心组件:

  1. 通道(channel):负责管道节点的连接及数据的运输
  2. 缓冲区(buffer):负责数据的存取
  3. 选择器(selector):是selectableChannel的多路复用器,用于监控SelectableChannel的IO状况。

SocketChannel: 是通道Channel重要的实现类,用于TCP协议的网络通信,用于实现网络通讯客户端的应用程序;
ServerSocketChannel: 是通道Channel重要的实现类,用于监听TCP连接请求,主要用于实现网络通讯服务器端的应用程序。

阻塞与非阻塞

  1. 阻塞式
    传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write()
    时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不
    能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会
    阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,
    当服务器端需要处理大量客户端时,性能急剧下降。
  2. 非阻塞式
    Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数
    据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时
    间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入
    和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同
    时处理连接到服务器端的所有客户端。

利用Java NIO网络通讯应用程序的操作步骤和示意图
Java 在使用NIO进行网络编程时,多线程应用程序的操作步骤和示意图如下所示:
处理步骤:

  1. 创建通道:
    打开一个或多个通道,例如FileChannel、SocketChannel等。
    创建缓冲区:为每个通道创建一个或多个缓冲区,用于读取或写入数据。
  2. 注册通道:
    将通道注册到选择器,以便选择器可以监控这些通道的状态。
  3. 选择就绪通道:
    选择器等待通道就绪事件,一旦有通道准备好进行I/O操作,选择器将通知应用程序。
  4. 读取/写入数据:
    应用程序从通道读取数据或将数据写入通道,使用缓冲区来传输数据。

在这里插入图片描述
其中,通道和缓冲区是一对一的关系。每个通道都有一个与之对应的缓冲区,用于存储数据。
选择器(Selector)可以同时监视多个通道的状态。一个选择器可以绑定多个通道,以实现多路复用。

我们先来看一个网络通信应用的例程,客户端采用NIO实现,而服务端依旧使用IO实现。

采用NIO的客户端程序源代码:

package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.TimeUnit;
public class SocketClientNIO {public static void client(){ByteBuffer buffer = ByteBuffer.allocate(1024);SocketChannel socketChannel = null;try{SocketAddress server = new InetSocketAddress("127.0.0.1",8080);socketChannel = SocketChannel.open();socketChannel.configureBlocking(false); //非阻塞式socketChannel.connect(server);//与服务端连接成功if(socketChannel.finishConnect()) {int i=0;while(true){TimeUnit.SECONDS.sleep(1);String info = "客户端发送信息,第 "+i++ +"条";buffer.clear();buffer.put(info.getBytes("GBK"));buffer.flip(); //切换while(buffer.hasRemaining()){System.out.println(buffer);socketChannel.write(buffer);}}}}catch (IOException | InterruptedException e){e.printStackTrace();}finally{try{if(socketChannel!=null){socketChannel.close();}}catch(IOException e){e.printStackTrace();}}}public static void main(String[] args) {SocketClientNIO.client();}
}

采用标准的IO实现的阻塞式网络通信服务器端程序的源代码:

package nio;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;public class SocketServerIO {public static void server(){ServerSocket serverSocket = null;InputStream in = null;try{serverSocket = new ServerSocket(8080);System.out.println("服务器开启,等待接收客户端连接");int recvMsgSize = 0;byte[] recvBuf = new byte[1024];while(true){Socket client = serverSocket.accept();SocketAddress clientAddr = client.getRemoteSocketAddress();System.out.println("接收到客户端,连接IP: "+clientAddr);in = client.getInputStream();while((recvMsgSize=in.read(recvBuf))!=-1){byte[] temp = new byte[recvMsgSize];System.arraycopy(recvBuf, 0, temp, 0, recvMsgSize);System.out.println("报文:"+new String(temp,"GBK"));}}}catch (IOException e){e.printStackTrace();}finally{try{if(serverSocket!=null){serverSocket.close();}if(in!=null){in.close();}}catch(IOException e){e.printStackTrace();}}}public static void main(String[] args) {SocketServerIO.server();}}

首先,编译后执行服务端应用程序,开启服务器服务,以接受客户端的请求;然后,编译执行客户端的应用程序。下面是服务端的测试效果:
在这里插入图片描述

未完待续

参考文献&博客:

  1. 参考文献之一
    攻破JAVA NIO技术壁垒
  2. 参考文献之二
    Java NIO全面详解(看这篇就够了)

http://www.ppmy.cn/ops/100597.html

相关文章

计算机毕业设计推荐-基于python的新能源汽车销售数据可视化分析【python-爬虫-大数据定制】

💖🔥作者主页:毕设木哥 精彩专栏推荐订阅:在 下方专栏👇🏻👇🏻👇🏻👇🏻 实战项目 文章目录 实战项目 一、基于python的新能源汽车销售…

modbus协议举例(03功能码)

Modbus协议是一种广泛使用的通信协议,通常用于工业自动化和控制系统。以下是Modbus协议的一个简单示例,展示如何通过Modbus RTU进行数据读取。 示例场景 假设我们有一个Modbus从设备,其地址为1,支持读取保持寄存器。我们希望读取…

MVVM分层思想

M:Model数据模型 V:View视图 VM:ViewModel视图模型 Vue也是借鉴了MVVM的思想 在Vue中,M就是data,V指挂载点,而Vue实例本身就是一个VM <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X…

语言基础/单向链表的构建和使用(含Linux中SLIST的解析和使用)

文章目录 概述简单的链表描述链表的术语简单实现一个单链表 Linux之SLIST机理分析结构定义单链表初始化单链表插入元素单链表遍历元素单链表删除元素 Linux之SLIST使用实践纯C中typedef重命名带来的问题预留 概述 本文讲述了数据结构中单链表的基本概念&#xff0c;头指针、头…

从0到1构建视频汇聚生态:EasyCVR视频汇聚平台流媒体协议支持的前瞻性布局

TSINGSEE青犀EasyCVR视频汇聚平台是一款基于云-边-端一体化架构的视频融合AI智能分析平台&#xff0c;广泛应用于工地、仓储、工厂、社区、校园、楼宇等多个领域。平台凭借其强大的数据接入、处理、转码及分发能力&#xff0c;在视频监控领域展现出显著的技术优势和应用前景。本…

python web 框架 Tornado

tornado.web.Application 是 Tornado 框架中的一个核心类&#xff0c;用于管理和配置 Web 应用程序。Tornado 是一个轻量级的异步网络框架&#xff0c;特别适合需要处理大量并发连接的应用程序&#xff0c;如实时 Web 服务、聊天应用或长轮询服务。 tornado.web.Application 的…

js导出方式及引入方式

默认导出 一个文件只能有一个 export default A;常规导出 一个文件可以有N个 export A; export B; export C;实际使用中 不冲突&#xff0c;可以同时使用。 export B; export C; export default A;常规导出单个 //a.js export const A () > {console.log(A) }//b.js im…

七、SPA单页面实现SEO优化之SSR服务器渲染

文章目录 一、前言&#xff1a;二、SSR基本操作步骤 一、前言&#xff1a; 关于SPA和SEO优化、SSR服务器渲染的介绍可以参考这里&#xff1a; 六、什么是SEO优化&#xff08;搜索引擎优化&#xff09;&#xff1f;SPA单页面应用如何实现SEO优化&#xff1f; 通过上一篇文章可…