【深入理解Java IO流0x0A】NIO实战-网络聊天室

本篇博客将进行NIO编程实战,实现一个简单聊天室。
我们来通过 SocketChannel 和 ServerSocketChannel 实现一个 0.1 版的聊天室,先说一下需求,比较简单,服务端启动监听客户端请求,当客户端向服务器端发送信息后,服务器端接收到后把客户端消息回显给客户端,比较呆瓜,但可以先来看一下。
image.png
来看服务端代码:

@Slf4j
public class ChatServer {private Selector selector;private ServerSocketChannel serverSocketChannel;private static final int PORT = 8080;public static void main(String[] args) {new ChatServer().start();}public ChatServer(){try {// 创建一个 ServerSocketChannel,并将其绑定到指定端口serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(PORT));// 设置为非阻塞模式serverSocketChannel.configureBlocking(false);// 创建一个Selector,并将ServerSocketChannel注册到它上面// 监听OP_ACCEPT事件(等待客户端连接)selector = Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);log.info("聊天室服务端启动了:"+PORT);} catch (IOException e) {e.printStackTrace();}}public void start(){try {// 无限循环,等待连接while(true){// 等待已注册的通道中有事件发生if(selector.select()>0){Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while(iterator.hasNext()){// 获取到发生事件的通道的SelectionKeySelectionKey key = iterator.next();iterator.remove();handleKey(key);}}}} catch (IOException e) {e.printStackTrace();}}// 判断SelectionKey的事件类型private void handleKey(SelectionKey key) throws IOException{// 如果是OP_ACCEPT事件,说明有新的客户端连接进来。// 接受新的连接,并将新连接的SocketChannel注册到 Selector上,监听OP_READ事件if(key.isAcceptable()){SocketChannel socketChannel = serverSocketChannel.accept();socketChannel.configureBlocking(false);socketChannel.register(selector,SelectionKey.OP_READ);log.info("客户端连接上了:"+socketChannel.getRemoteAddress());}else if(key.isReadable()){  // 如果是OP_READ事件,说明客户端发送了消息。读取客户端发送的消息,并将其返回给客户端SocketChannel socketChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int len = socketChannel.read(buffer);if(len>0){buffer.flip();String message = new String(buffer.array(),0,len);log.info("客户端说:"+message);String responseMsg = "服务端回复:"+message;socketChannel.write(ByteBuffer.wrap(responseMsg.getBytes()));}}}
}

接下来是客户端:

@Slf4j
public class ChatClient {private Selector selector;private SocketChannel socketChannel;private static final String HOST = "localhost";private static final int PORT = 8080;public static void main(String[] args) {new ChatClient().start();}public ChatClient(){try {selector = Selector.open();// 创建一个 SocketChannel,并连接到指定的服务器地址和端口socketChannel = SocketChannel.open(new InetSocketAddress(HOST,PORT));socketChannel.configureBlocking(false); // 设置为非阻塞模式// 将SocketChannel注册到selector上面,监听OP_READ事件(等待接收服务器的消息)socketChannel.register(selector, SelectionKey.OP_READ);log.info("连接到聊天室了");} catch (IOException e) {e.printStackTrace();}}private void start() {// 启动一个新线程用于new Thread(()->{try {while(true){// 等待已注册的通道中有事件发生if(selector.select()>0){// 获取到发生事件的通道的 SelectionKeyfor(SelectionKey key:selector.selectedKeys()){selector.selectedKeys().remove(key);// 如果是 OP_READ 事件,说明服务器发送了消息。读取服务器发送的消息,并在控制台显示。if(key.isReadable()){readMessage();}}}}} catch (Exception e) {e.printStackTrace();}}).start();try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){String input;while((input=reader.readLine())!=null){sendMessage(input);}}catch (IOException e){e.printStackTrace();}}private void sendMessage(String message) throws IOException{if(message!=null && !message.trim().isEmpty()){ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());socketChannel.write(buffer);}}private void readMessage() throws IOException{ByteBuffer buffer = ByteBuffer.allocate(1024);int len = socketChannel.read(buffer);if(len>0){buffer.flip();String message = new String(buffer.array(),0,len);log.info(message);}}
}

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

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

相关文章

如何落地一个FaaS平台?

简介&#xff1a; 函数即服务&#xff08;FaaS&#xff09;作为云计算 2.0 时代重要的发展方向&#xff0c;能够从工程效率、可靠性、性能、成本等方面给开发者带来巨大的价值&#xff0c;尤其是能够极大地提升研发效率。因此&#xff0c;拥抱FaaS成为开发者关心的重要技术领域…

FPGA - 仲裁器的设计实现

一&#xff0c;为什么做仲裁 在多主单从的设计中&#xff0c;当多个源端同时发起传输请求时&#xff0c;这个时候就需要仲裁器来根据优先级来判断响应哪一个源端&#xff0c;向其传输数据。比如&#xff1a;以太网仲裁&#xff0c;DDR仲裁&#xff0c;光纤传图仲裁..... 二&a…

【Java开发指南 | 第二篇】标识符、Java关键字及注释

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 标识符Java关键字Java注释 标识符 Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。 所有的标识符都应该以字母&#xff08;A-Z 或者 a-z&#xff09;,美元符&#xff08;$&#xff0…

从51到ARM裸机开发实验(009)LPC2138 中断实验

一、场景设计 中断的概念在《从51到ARM裸机开发实验(007) AT89C51 中断实验》中已经介绍过&#xff0c;LPC2138的Keil工程创建在《从51到ARM裸机开发实验(005)LPC2138 GPIO实验》中已经介绍过。本次使用LPC2138来实现一个这样的场景&#xff1a;四个LED依次亮灭&#xff0c;时间…

蓝桥杯2024年第十五届省赛

E:宝石组合 根据给的公式化简后变为gcd(a,b,c)根据算数基本定理&#xff0c;推一下就可以了 然后我们对1到mx的树求约数&#xff0c;并记录约数的次数&#xff0c;我们选择一个最大的且次数大于等3的就是gcd int mx; vector<int> g[N]; vector<int> cnt[N]; int…

如何应对MySQL单表数据量过大:垂直分表与水平分表策略解析

话接上回&#xff0c;单表最大数据建议两千万&#xff0c;那如果开发一个项目&#xff0c;预计注册量达到一个亿怎么办。 单表内放这么多数据&#xff0c;MYSQL底层B树的层级结构就可能会变得很高&#xff0c;磁盘io次数变多&#xff0c;性能会大幅度降低。所以考虑数据库分表…

光场相机建模与畸变校正改进方法

摘要&#xff1a;光场相机作为一种新型的成像系统&#xff0c;可以直接从一次曝光的图像中得到三维信息。为了能够更充分有效地利用光场数据包含的角度和位置信息&#xff0c;完成更加精准的场景深度计算&#xff0c;从而提升光场相机的三维重建的精度&#xff0c;需要实现精确…

大规模端云协同智能计算(大小模型端云协同联合学习)

原文作者&#xff1a;上海交通大学 吴帆 0 引言 目前&#xff0c;许多智能技术已经走入人们的日常生活&#xff0c;例如交互式商品推荐、人脸识别、语音识别、体征观测、疾病诊断、智能决策等&#xff0c;这些智能技术在为我们生活带来极大便利的同时&#xff0c;也深刻改变了…

解决VS2022创建项目只有解决方案看不到项目文件

问题&#xff1a;无法运行、看不到项目文件 解决&#xff1a; 检查环境变量是否正确

金属棒直线度测量仪:在线精准测量的关键工具

在现代工业生产中&#xff0c;金属棒的直线度是一个至关重要的参数。它的微小变化&#xff0c;直接关系到产品质量的优劣&#xff0c;因此准确测量金属棒的直线度成为了生产过程中的关键环节。 金属棒在线直线度测量仪应运而生&#xff0c;它是一种专门用于测量金属棒直线度的精…

秋招复习笔记——八股文部分:网络基础

TCP/IP 网络模型 应用层 最上层的&#xff0c;也是我们能直接接触到的就是应用层&#xff08;Application Layer&#xff09;&#xff0c;我们电脑或手机使用的应用软件都是在应用层实现。那么&#xff0c;当两个不同设备的应用需要通信的时候&#xff0c;应用就把应用数据传…

软件测试面试题分享(含答案+文档)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 准备找工作的小伙伴们&#xff0c;今天我给大家带来了一些自动化测试面试题&#xff0c;在这个公…