java NIO 实例之多人聊天
关键抽象
1.定义一个HashMap<String,SocketChannel>用户存储每个用户的管道。
2.服务端监听read事件,获取消息后轮询hashmap发送消息给用户模型内的所有用户
3.客户端简单read事件,读取聊天消息;发送消息给服务端
1.服务端代码
package com.leam.springboot.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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID; /**
* NIO服务端转发个所有客户端
*/
public class NioServer {
private static Selector selector; /**
* 开启一个服务端
* 设置为非阻塞
* 绑定端口号
* backlog 处理的最大连接数,大于这个数直接拒绝
*/
static { try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(9999));
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
} public static void server() throws IOException {
Map<String, SocketChannel> clientMap = new HashMap<>(0);
while (true) {
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
selectionKeys.forEach(selectionKey -> {
try { if (selectionKey.isAcceptable()) {
/**
* 服务器接收到客户端链接
* 保存接收到的客户端链接
*/
ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();
SocketChannel channel = server.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
String key = UUID.randomUUID().toString();
clientMap.put(key, channel);
System.out.println(channel.getRemoteAddress() + "链接上服务器");
} else if (selectionKey.isReadable()) {
/**
* 读取客户端消息
* 转发到所有客户端
*/
try {
SocketChannel channel = (SocketChannel) selectionKey.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = channel.read(buffer);
if (len > 0) {
buffer.flip();
Charset charset = Charset.forName("UTF-8");
String receiveMsg = String.valueOf(charset.decode(buffer).array());
String key = null;
for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {
if (entry.getValue() == channel) {
key = entry.getKey();
break;
}
}
String sendMsg = key + ":" + receiveMsg;
System.out.println(sendMsg);
for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {
ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
writeBuffer.put(charset.encode(sendMsg));
writeBuffer.flip();
entry.getValue().write(writeBuffer);
}
}
} catch (Exception e) {
e.printStackTrace(); System.out.println("远程主机强迫关闭了一个现有的连接11111");
}
} } catch (Exception e) {
System.out.println("服务端出来异常");
}
});
selectionKeys.clear();
}
} public static void main(String args[]) throws IOException {
server();
} }
2.客户端代码
package com.leam.springboot.nio; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* 客户端注册
*/
public class NioClient {
private static Selector selector;
/**
* 开启一个服务端
* 设置为非阻塞
* 连接到服务器
*/
static { try {
SocketChannel socketChannel=SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("localhost",9999));
selector=Selector.open();
socketChannel.register(selector, SelectionKey.OP_CONNECT);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void client() throws IOException {
Map<String,SocketChannel> clientMap=new HashMap<>(0);
while (true) {
selector.select();
Set<SelectionKey> selectionKeys=selector.selectedKeys();
selectionKeys.forEach( selectionKey -> {
try {
if (selectionKey.isConnectable()) {
/**
* 客户端已连接
* 开启一个线程监听控制台输入
*/
SocketChannel client = (SocketChannel) selectionKey.channel();
if (client.isConnectionPending()) { client.finishConnect(); }
client.register(selector,SelectionKey.OP_READ);
// for(int i=0;i<5;i++){
ExecutorService executor = Executors.newSingleThreadExecutor();
System.out.println(client.getLocalAddress()+"连上了服务器");
ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
executor.submit(()->{
try {
while (true) {
writeBuffer.clear();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line = reader.readLine();
writeBuffer.put(line.getBytes());
writeBuffer.flip();
client.write(writeBuffer);
}
}catch (Exception e) {
e.printStackTrace();
}
});
// }
} else if (selectionKey.isReadable()) {
/**
* 打印服务端消息
*/
SocketChannel client = (SocketChannel) selectionKey.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int len = client.read(readBuffer);
System.out.println(new String(readBuffer.array(),0,len));
}
} catch (Exception e) {
e.printStackTrace();
}
});
selectionKeys.clear();
} }
public static void main(String args[]) throws IOException {
client();
}
}
java NIO 实例之多人聊天的更多相关文章
- Java NIO示例:多人网络聊天室
一个多客户端聊天室,支持多客户端聊天,有如下功能: 功能1: 客户端通过Java NIO连接到服务端,支持多客户端的连接 功能2:客户端初次连接时,服务端提示输入昵称,如果昵称已经有人使用,提示重新输 ...
- java swing+socket实现多人聊天程序
swing+socket实现多人聊天程序 1.准备工作 先看效果: 客户端项目结构图: 服务端项目结构图: 2.运行原理 服务端 先开一个线程serverListerner,线程中开启一个Server ...
- Java使用socket实现两人聊天对话
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; /* ...
- Java NIO 聊天室实例
最近写了个Java NIO聊天室聊天的程序,NIO学习起来比较困难的,我的代码能给大家起到一个抛砖引玉的作用! 服务端: package test.javanio; /** * @author * @ ...
- Java NIO实战之聊天室
在工作之余花了两个星期看完了<Java NIO>.整体来说这本书把NIO写的非常具体,没有过多的废话,讲的都是重点,仅仅是翻译的中文版看的确实吃力.英文水平太低也没办法,总算也坚持看完了. ...
- Java nio socket与as3 socket(粘包解码)连接的应用实例
对Java nio socket与as3 socket连接的简单应用 <ignore_js_op>Java nio socket与as3 socket连接的应用实例.rar (9.61 K ...
- Java NIO原理及实例
Java NIO是在jdk1.4开始使用的,它既可以说成“新I/O”,也可以说成非阻塞式I/O.下面是java NIO的工作原理: 1. 由一个专门的线程来处理所有的 IO 事件,并负责分发. 2. ...
- java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端
java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端 启动界面如下图: 首先启动服务器: 客户端登陆,登陆成功后为: 默认发送是全部用户,是多人发送. 当在边列 ...
- 多人聊天室(Java)
第1部分 TCP和UDP TCP:是一种可靠地传输协议,是把消息按一个个小包传递并确认消息接收成功和正确才发送下一个包,速度相对于UDP慢,但是信息准确安全:常用于一般不要求速度和需要准确发送消息的场 ...
随机推荐
- 聊一聊高并发高可用那些事 - Kafka篇
目录 为什么需要消息队列 1.异步 :一个下单流程,你需要扣积分,扣优惠卷,发短信等,有些耗时又不需要立即处理的事,可以丢到队列里异步处理. 2.削峰 :按平常的流量,服务器刚好可以正常负载.偶尔推出 ...
- mysql中drop、delete、truncate的区别简述
一.区别 1.去什么? truncate table 和 delete只删除数据(记录)不删除表的结构;drop语句将删除表的数据(记录)和表结构依赖的约束(constrain),触发器(trigge ...
- kvm的命令简单使用
virsh命令常用参数总结 参数 参数说明 基础操作 list 查看虚拟机列表,列出域 start 启动虚拟机,开始一个(以前定义的)非活跃的域 shutdown 关闭虚拟机,关闭一个域 dest ...
- javaScript的执行机制-同步任务-异步任务-微任务-宏任务
一.概念理解 1.关于javascript javascript是一门单线程语言,在最新的HTML5中提出了Web-Worker,但javascript是单线程这一核心仍未改变.所以一切javascr ...
- HDU - 3591 The trouble of Xiaoqian 题解
题目大意 有 \(N\) 种不同面值的硬币,分别给出每种硬币的面值 \(v_i\) 和数量 \(c_i\).同时,售货员每种硬币数量都是无限的,用来找零. 要买价格为 \(T\) 的商品,求在交易中最 ...
- Spring杂谈 | 从桥接方法到JVM方法调用
前言 之所以写这么一篇文章是因为在Spring中,经常会出现下面这种代码 // 判断是否是桥接方法,如果是的话就返回这个方法 BridgeMethodResolver.findBridgedMetho ...
- 循环语句&编码了解
循环语句&编码了解 用户交互 input: input接收的内容是str 循环语句 if语句 语法规则: if 条件判断: 代码块1 else ...
- EIGRP-10-弥散更新算法-计算距离,报告距离,可行距离和可行性条件
对于某个目的网络,EIGRP持续关注它的各种距离参数.EIGRP使用复合度量参数,不过为了简化,这里使用一个没有单位的数值.同样出于简化,这里的EIGRP路由器都不使用水平分割.
- 网络聚合Network Teaming
team是新的聚合软件,依赖于安装包teamd,可以通过nmcli管理. team和bond的区别在于,支持hash加密,支持负载均衡,支持8块网卡,更好地支持IPV6,总之要取代bond. 1. 添 ...
- @bzoj - 2658@ [Zjoi2012]小蓝的好友(mrx)
目录 @description@ @solution@ @accepted code@ @details@ @description@ 终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事 ...