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慢,但是信息准确安全:常用于一般不要求速度和需要准确发送消息的场 ...
随机推荐
- vim编辑器添加插件NERDTree
0x01 首先在 http://www.vim.org/scripts/script.php?script_id=1658 下载插件 (可能要爬梯,也可以在https://github.com/scr ...
- 华为EMUI在service中不能打印debug级别的日志
华为emui在service里面不能打印debug级别的日志,因为这个小问题调试了一上午,刚开始我还以为emui把系统service的启动流程都改了呢
- 【Spring注解驱动开发】使用@Lazy注解实现懒加载
写在前面 Spring在启动时,默认会将单实例bean进行实例化,并加载到Spring容器中.也就是说,单实例bean默认在Spring容器启动的时候创建对象,并将对象加载到Spring容器中.如果我 ...
- KMP 知识点整理
1.扩展KMP 2.最大表示法 3.最小表示法 (扩展KMP) hdu2594 模板题 #include <iostream> #include <cstdio> #incl ...
- throws,throw,try,catch,finally 分别代表什么 意义?
Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口. 在Java中,每个异常都是一个对象,它是Throwable类或其它子类的实例.当一个方法出现异常后便 抛出一个异 ...
- Clear Writer v1.7 更新
拖更了这么久了的我终于来更新了--这可能是今年上半年最后一次更新了-- 这次我打算把 Clear Writer 公开发布了. 下载链接 下载链接在这里. (这次用蓝奏,不用奶牛快传了) Clear W ...
- Kubernetes-subpath的使用
一.什么是subpath 为了支持单一个pod多次使用同一个volume而设计,subpath翻译过来是子路径的意思,如果是数据卷挂载在容器,指的是存储卷目录的子路径,如果是配置项configMap/ ...
- cookie,session,jwt,token,oauth2联系和区别
为啥有这么多的东西? 由于互联网在刚开始设计的时候是展现静态网页为主,没有现在这么多的交互和互动,所以被设计为了无状态,随用随走的简单模式.随着互联网的发展,各种具有和用户交互功能的网站出现,要求用户 ...
- 暑假集训Day2 互不侵犯(状压dp)
这又是个状压dp (大型自闭现场) 题目大意: 在N*N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. ...
- Exception in thread "main" java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%7Bsystem:user.name%7D
问题原因是Hive里面配置的相对路径没有找到,我们可以直接在文件里面修改为绝对路径. 1.在hive下面窗口temp文件夹 cd /opt/hive mkdir temp cd temp 2.查看te ...