NIO通信代码示例

NIO通信架构图

在这里插入图片描述

1.Client

NioClient

package nio;import constant.Constant;import java.io.IOException;
import java.util.Scanner;public class NioClient {private static NioClientHandle nioClientHandle;public static void start() {nioClientHandle = new NioClientHandle(Constant.DEFAULT_SERVER_IP, Constant.DEFAULT_PORT);new Thread(nioClientHandle, "Client").start();}// 向服务器发送消息public static boolean sendMsg(String msg) throws IOException {nioClientHandle.sendMsg(msg);return true;}public static void main(String[] args) throws IOException {start();Scanner scanner = new Scanner(System.in);while (NioClient.sendMsg(scanner.next()));}
}

NioClientHandle

package nio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class NioClientHandle implements Runnable {private String host;private int port;private volatile boolean started;private Selector selector;private SocketChannel socketChannel;public NioClientHandle(String ip, int port) {this.host = ip;this.port = port;try {// 创建选择器的实例selector = Selector.open();// 创建ServerSocketChannel的实例socketChannel = SocketChannel.open();// 设置通道为非阻塞模式socketChannel.configureBlocking(false);started = true;} catch (Exception e) {e.printStackTrace();}}public void stop() {started = false;}@Overridepublic void run() {try {doConnect();} catch (Exception e) {e.printStackTrace();System.exit(1);}// 循环遍历selectorwhile (started) {try {// 无论是否有读写事件发生,selector每隔1s被唤醒一次selector.select(1000);// 获取当前有哪些事件可以使用Set<SelectionKey> keys = selector.selectedKeys();// 转换为迭代器Iterator<SelectionKey> it = keys.iterator();SelectionKey key = null;while (it.hasNext()) {key = it.next();// 我们必须受限将处理过的SelectionKey从选定的集合中删除// 如果我们没有删除处理过的键,那么它仍然会在主集合中以一个激活的键// 出现,这会导致我们尝试再次处理它it.remove();try {handleInput(key);} catch (Exception e) {if (key != null) {key.cancel();if (key.channel() != null) {key.channel().close();}}}}} catch (Exception e) {e.printStackTrace();System.exit(1);}}// selector关闭后会自动释放里面管理的资源if (selector != null) {try {selector.close();} catch (Exception e) {e.printStackTrace();}}}/*** 具体的事件处理方法* @param key*/private void handleInput(SelectionKey key) throws IOException {if (key.isValid()) {// 获得关心当前事件的channelSocketChannel sc = (SocketChannel)key.channel();// 连接事件if (key.isConnectable()) {if (sc.finishConnect()) {socketChannel.register(selector, SelectionKey.OP_READ);} else {System.exit(1);}}// 有数据可读事件if (key.isReadable()) {// 创建ByteBuffer,并开启一个1M的缓冲区ByteBuffer buffer = ByteBuffer.allocate(1024);// 读取数据码流 返回读取到的字节数int readBytes = sc.read(buffer);// 读取到字节 对字节进行编解码if (readBytes > 0) {//将缓冲区当前的limit设置为position, position = 0;// 用于后续对缓冲区的读取操作buffer.flip();// 根据缓冲区可读字节数创建字节数组byte[] bytes = new byte[buffer.remaining()];// 将缓冲区可读字节数组复制到新建的数组中buffer.get(bytes);String result = new String(bytes, "UTF-8");System.out.println("客户端收到消息:" + result);} else if (readBytes < 0) {key.cancel();sc.close();}}}}public void sendMsg(String msg) throws IOException {doWrite(socketChannel, msg);}private void doWrite(SocketChannel socketChannel, String request) throws IOException {// 将消息编码为字节数组byte[] bytes = request.getBytes();// 根据数组容量创建ByteBufferByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);// 将字节数组复制到缓冲区writeBuffer.put(bytes);// flip操作writeBuffer.flip();// 发送缓冲区的字节数组// 关心事件和读写网络不冲突socketChannel.write(writeBuffer);}private void doConnect() throws IOException {// 非阻塞的连接if (socketChannel.connect(new InetSocketAddress(host, port))) {socketChannel.register(selector, SelectionKey.OP_READ);} else {socketChannel.register(selector, SelectionKey.OP_CONNECT);}}
}

2.Server

NioServer

package nio;import constant.Constant;public class NioServer {private static NioServerHandle nioServerHandle;public static void main(String[] args) {nioServerHandle = new NioServerHandle(Constant.DEFAULT_PORT);new Thread(nioServerHandle, "Server").start();}
}

NioServerHandle

package nio;import constant.Constant;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class NioServerHandle implements Runnable {private volatile boolean started;private ServerSocketChannel serverSocketChannel;private Selector selector;public NioServerHandle(int port) {try {// 创建选择器实例selector = Selector.open();// 创建ServerSocketChannel的实例serverSocketChannel = ServerSocketChannel.open();// 设置通道为非阻塞模式serverSocketChannel.configureBlocking(false);// 绑定端口serverSocketChannel.socket().bind(new InetSocketAddress(port));// 注册事件,表示关心客户端连接serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// started = true;System.out.println("服务器已启动, 端口号为:" + port);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void run() {while (started) {try {// 获取当前有哪些事件selector.select(1000);// 获取事件的集合Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();// 我们必须首先将处理过的SelectionKey 从选定的键集合中删除// 如果我们没有删除处理过的键,那么它仍然会在主集合中以// 一个激活的键出现,这回导致我们尝试再次处理它iterator.remove();handleInput(key);}} catch (Exception e) {}}}/*** 处理事件的发生* @param key*/private void handleInput(SelectionKey key) throws IOException {if (key.isValid()) {// 处理新接入的客户端的请求if (key.isAcceptable()) {// 获取关心当前事件的ChannelServerSocketChannel ssc = (ServerSocketChannel)key.channel();// 接受连接SocketChannel sc = ssc.accept();System.out.println("=========建立连接=========");sc.configureBlocking(false);// 关注读事件sc.register(selector, SelectionKey.OP_READ);}// 处理对端的发送的数据if (key.isReadable()) {SocketChannel sc = (SocketChannel) key.channel();// 创建ByteBuffer, 开辟一个缓冲区ByteBuffer buffer = ByteBuffer.allocate(1024);// 从通道里读取数据,然后写入bufferint readBytes = sc.read(buffer);if (readBytes > 0) {// 将缓冲区当前的limit设置为position, position = 0// 用于后续对缓冲区的读取操作buffer.flip();// 根据缓冲区可读字节数创建字节数组byte[] bytes = new byte[buffer.remaining()];// 将缓冲区可读字节数组复制到新建的数组中buffer.get(bytes);String message = new String(bytes, "UTF-8");System.out.println("服务器收到消息:" + message);// 处理数据String result = Constant.response(message);// 发送应答消息doWrite(sc, result);}}}}private void doWrite(SocketChannel sc, String response) throws IOException {byte[] bytes = response.getBytes();ByteBuffer buffer = ByteBuffer.allocate(bytes.length);buffer.put(bytes);buffer.flip();sc.write(buffer);}
}

3.代码运行实例

先启动server再启动client
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/613998.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3 快速前端开发

3 前端JavaScript 3 前端JavaScript1. JavaScript1.1 代码位置1.2 注释1.3 变量1.4 字符串类型案例&#xff1a;跑马灯 1.5 数组案例&#xff1a;动态数据 1.6 对象&#xff08;字典&#xff09;案例&#xff1a;动态表格 1.7 条件语句1.8 函数 2.DOM2.1 事件的绑定 3.知识点的…

redis中的string相关的部分命令

redis命令手册 redis中文官网查看文档 挨个进行输出调试 Redis Setnx 命令 Redis Getrange 命令 Redis Mset 命令 redis 127.0.0.1:6379> MSET key1 "Hello" key2 "World" OK redis 127.0.0.1:6379> GET key1 "Hello" redis 127.0.0.1:…

LLVM的安装步骤实战

目录 1. 准备环境 1.1 安装必备软件包 1.2 配置Git 2. 用CMake构建 2.1 克隆代码库 2.2 创建构建目录 2.3 生成构建系统文件 3. 自定义构建 3.1 CMake定义的变量 3.2 LLVM定义的变量 4. 总结 1. 准备环境 首先操作系统可以是Linux、FreeBSD、macOS或Windows。 同…

2.【CPP】入门(宏||内联函数||拷贝构造||析构函数||构造函数)

0x01.引言 1.实现一个宏函数ADD #define ADD(x,y) ((x)(y))//宏是预编译阶段完成替换&#xff0c;注意括号2.宏的优缺点 优点&#xff1a; 1.增强代码的复用性 2.宏函数不用建立栈帧&#xff0c;提高性能 缺点&#xff1a; 1.不方便调试 2.没有安全检查 0x02.内联函数 1.以空…

可狱可囚的爬虫系列课程 11:Requests中的SSL

一、SSL 证书 SSL 证书是数字证书的一种&#xff0c;类似于驾驶证、护照、营业执照等的电子副本。SSL 证书也称为 SSL 服务器证书&#xff0c;因为它是配置在服务器上。 SSL 证书是由受信任的数字证书颁发机构 CA 在验证服务器身份后颁发的&#xff0c;其具有服务器身份验证和…

base64与BytesIO图片进行编码、解码;api调用

base64与BytesIO简单介绍 io.BytesIO 和 Base64 编码都是用于在内存中处理二进制数据的方法&#xff0c;但它们的目的和使用场景有所不同。 1&#xff09; io.BytesIO io.BytesIO 是 Python io 库中的一个类&#xff0c;它提供了一个在内存中处理二进制数据的接口&#xff0…

Linux最常用的几个时间日期命令

文章目录 Linux最常用的几个时间日期命令一日难再晨及时当勉励 date默认输入显示时区世界协调时格式化日期 时光总是催人老 time语法示例 休息一会 sleep休息5分钟1小时后提醒我时分秒搭配使用倒计时计时器结合脚本 更多信息 Linux最常用的几个时间日期命令 桃花谢了春红&…

如何在Docker本地搭建流程图绘制神器draw.io并实现公网远程访问

推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 前言 提到流程图&#xff0c;大家第一时间可能会想到Visio&#xff0c;不可否认&#xff0c;VIsio确实是功能强大&#xff0c;但是软…

C++里main函数int main(int argc, char **argv)

C里main函数int main(int argc, char **argv), 这两个参数argc和argv分别是什么

Vue3组件库 -- element plus 树形选择器组件怎样显示已有的树形菜单?

<el-tree-selectv-model"form.topmneu":data"tableData":props"{ label: title, value: id }":render-after-expand"false"style"width: 100%"check-strictly/> 添加 :props "{ lable : 字段名 , value: 字段…

极客时间-读多写少型缓存设计

背景 内容是极客时间-徐长龙老师的高并发系统实战课的个人学习笔记&#xff0c;欢迎大家学习&#xff01;https://time.geekbang.org/column/article/596644 总览内容如下&#xff1a; 缓存性价比 一般来说&#xff0c;只有热点数据放到缓存才更有价值 数据量查询频率命中…

java基础之异常练习题

异常 1.Java 中所有的错误/异常都继承自 Throwable类&#xff1b;在该类的子类中&#xff0c; Error 类表示严重的底层错误&#xff0c; 对于这类错误一般处理的方式是 直接报告并终止程序 &#xff1b; Exception 类表示异常。 2.查阅API&#xff0c;完成以下填空&#xff1a;…

leetcode动态规划(零钱兑换II、组合总和 Ⅳ)

518.零钱兑换II 给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。 示例 1: 输入: amount 5, coins [1, 2, 5] 输出: 4 解释: 有四种方式可以凑成总金额: 55 5221 52111 511111 示例 2: 输入: amount 3, coi…

【江科大STM32单片机】day1点亮LED灯流水灯蜂鸣器

知识点 推挽模式&#xff1a;高-》低、低-》高电平都能驱动 开漏模式&#xff1a;只能低-》高电平能驱动&#xff0c;高电平相当于高阻态 GPIO_WriteBit 操作单个 GPIO_ResetBits 操作同组 3-2 led闪烁 配置相关驱动 USE_STDPERIPH_DRIVER 配置输出文件格式debug配置slink勾选…

基于Springboot的课程答疑系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的课程答疑系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

Python知识点(史上最全)

Python期末考试知识点&#xff08;史上最全&#xff09; python简介 Python是一种解释型语言 Python使用缩进对齐组织代码执行&#xff0c;所以没有缩进的代码&#xff0c;都会在载入时自动执行 数据类型&#xff1a;整形 int 无限大 浮点型 float…

小程序基础学习(组件化)

&#xff08;一&#xff09;创建 找到components文件夹下面创建新的文件夹 然后再文件夹内创建component格式的文件 创建后这样 我创建的是my-info的文件夹以及my-info的components文件&#xff0c;跟着普通的页面一样 &#xff08;二&#xff09; 注册组件 找到你需要使用组…

微信小程序-----宿主环境(组件介绍和代码编写)

目录 前言 宿主环境简介 1. 什么是宿主环境 ​编辑 2.小程序的宿主环境 3. 小程序宿主环境包含的内容 一、通信模型 1. 通信的主体 2. 小程序的通信模型 二、运行机制 1.小程序启动的过程 2.页面渲染的过程 三、组件 常用的视图容器类组件 1.view 组件 2.scroll-…

RK3399平台入门到精通系列讲解(驱动篇)eventpoll结构体详解

🚀返回总目录 文章目录 一、eventpoll 结构体二 、epitem 结构体三、eppoll_entry 结构体eventpoll 结构体:eventpoll 结构体是 epoll 在内核中的核心结构epitem 结构体:epitem 结构体用于表示 epoll 实例中的事件项eppoll_entry 结构体:它的作用就是关联Socket等待队列中…

MES数据采集在制造业的应用

MES设备数据采集的流程包括以下几个步骤&#xff1a; 1. 设备接入&#xff1a;将设备接入MES系统&#xff0c;建立设备与MES系统之间的连接。 2. 数据采集&#xff1a;通过传感器和采集器等设备&#xff0c;采集设备运行数据和状态信息。 3. 数据存储&#xff1a;将采集到的设…