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.hqwc.cn/news/340610.html

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

相关文章

面试算法115:重建序列

题目 长度为n的数组org是数字1&#xff5e;n的一个排列&#xff0c;seqs是若干序列&#xff0c;请判断数组org是否为可以由seqs重建的唯一序列。重建的序列是指seqs所有序列的最短公共超序列&#xff0c;即seqs中的任意序列都是该序列的子序列。 例如&#xff0c;如果数组org为…

Element|Upload结合Progress实现上传展示进度条

背景 &#xff1a; 项目里的 附件上传 题型组件&#xff0c;用户在上传过程中&#xff0c;如果文件较大&#xff0c;上传过程较慢&#xff0c;而又没有一个类似 Loading... 的加载过程的话&#xff0c;会显得干愣愣的&#xff0c;用户体验较差&#xff0c;所以需要添加一个进度…

Day4Qt

1.头文件: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTime>//时间类 #include <QTimer>//时间事件类 #include <QTimerEvent>//定时器类 #include <QTextToSpeech> namespace Ui { class Widget; }class Widget : publi…

OpenCV C++ 图像处理实战 ——《多尺度自适应Gamma矫正的低照图像增强》

OpenCV C++ 图像处理实战 ——《多尺度自适应Gamma矫正的低照图像增强》 一、结果演示二、多尺度自适应Gamma矫正的低照度图像增强2.1HSI颜色空间2.1.1 功能源码2.2 自适应于直方图分布的 Gamma 矫正2.2.1 功能源码2.3 多尺度 Retinex 分解与明度增强2.3.1 功能源码三、源码测试…

性能测试之Mysql数据库调优

一、前言 性能调优前提&#xff1a;无监控不调优&#xff0c;对于mysql性能的监控前几天有文章提到过&#xff0c;有兴趣的朋友可以去看一下 二、Mysql性能指标及问题分析和定位 1、我们在监控图表中关注的性能指标大概有这么几个&#xff1a;CPU、内存、连接数、io读写时间、…

x-cmd pkg | grex - 用于生成正则表达的命令行工具

目录 简介首次用户生成的正则表达式与 perl 和 rust 兼容支持 Unicode 符号友好的用户体验进一步阅读 简介 grex 是一个旨在简化创作正则表达式的复杂且繁琐任务的库和命令行程序。这个项目最初是 Devon Govett 编写的 JavaScript 工具 regexgen 的 Rust 移植。但 regexgen 在…

鸿蒙开发已解决-arkts编译报错-arkts-limited-stdlib错误

文章目录 项目场景:问题描述原因分析:解决方案:适配指导案例此Bug解决方案总结项目场景: arkts编译报错-arkts-limited-stdlib错误。 我用Deveco studio4.0 beta2开发应用,报arkts-limited-stdlib错误 报错内容为: ERROR: ArKTS:ERROR File: D:/prRevivw/3792lapplica…

SPI接口协议

SPI接口协议 SPI(Serial Peripheral Interface)是由Motorola公司定义的接口协议标准&#xff0c;串行外设接口(SPI)是微控制器和外围IC&#xff08;如传感器、 ADC、 DAC、移位寄存器、 SRAM等&#xff09;之间使用最广泛的接口之一。SPI是一种同步、全双工、主从式接口&#x…

通过两台linux主机配置ssh实现互相免密登陆

一、准备工作 1:两台Linux主机&#xff0c;需要能ping通 2:检查防火墙是否处于关闭状态,没关闭的话关闭&#xff0c;防止防火墙拦截流量 查看防火墙状态&#xff1a;systemctl status firewalld 关闭防火墙&#xff1a;systemctl stop firewalld 3:使用getenforce命令查…

ssm+vue的城投公司企业人事管理系统设计与实现(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的城投公司企业人事管理系统设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#x…

邻接矩阵、可达性矩阵、完全关联矩阵、可达性矩阵的计算

邻接矩阵&#xff1a;很简单&#xff0c;就是两个点有关系就是1&#xff0c;没有关系就是0 可达性矩阵&#xff1a;非常简单&#xff0c;两点之间有路为1&#xff0c;没有路为0 可发行矩阵的计算&#xff1a;有n个元素&#xff0c;初始可达性矩阵为A&#xff0c;那么最终的矩阵…

springboot框架开发的中小学智慧校园云平台源码

一、智慧校园技术框架 1、使用springboot框架Javavue2 B/S架构 2、JAVA语言数据库MySQL5.7 3、移动端小程序使用小程序原生语言开发 4、电子班牌固件安卓7.1&#xff1b;使用Java Android原生 5、elmentui &#xff0c;Quartz&#xff0c;jpa&#xff0c;jwt 6、前后端分离架…