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慢,但是信息准确安全:常用于一般不要求速度和需要准确发送消息的场 ...
随机推荐
- kebernets常用命令-整理
1.deployment相关命令 查看所有deployment: kubectl get deployments 查看指定命名空间的所有deployment: kubectl get deployme ...
- 2019-02-07 selenium...
今天是超级郁闷的一天 看教程 下了mysql-----配置-----不会----查资料------2小时后 mongodb-----配置------不会------查资料------1小时后 然后是各 ...
- uiautomatorviewer 截取手机屏幕报错
1. 解决办法: 1.在e盘新建一个文件夹,命名为app.uix 2.打开cmd命令,输入命令adb pull /sdcard/app.uix E:/app.uix 3.打开uiautomatorvi ...
- 使用Applescript、Automator和AfredWorkflow实现流式工作
重要:本文不会提供标题中三个工具的详细使用教程,只会对它们的进行简要的介绍.更高妙的使用技巧读者应自行钻研. 参考资料: 两个关于Applescript和Automator使用的PDF:https:/ ...
- Docker数据管理与挂载管理
介绍如何在 Docker 内部以及容器之间管理数据:在容器中管理数据主要有两种方式:数据卷(Volumes).挂载主机目录 (Bind mounts) 镜像来源 [root@docker01 ~]# ...
- 为什么启动线程是start方法?
为什么启动线程是start方法 十年可见春去秋来,百年可证生老病死,千年可叹王朝更替,万年可见斗转星移. 凡人如果用一天的视野,去窥探百万年的天地,是否就如同井底之蛙? 背景:启动线程是start ...
- django 注册后台管理 在debug=true能行,在debug=false不能显示出管理标签
debug=true 下,如下图:
- 上位机面试必备——TCP通信灵魂二十问【上】
关注公众号获取更多干货 TCP通信协议应该是上位机开发中应用最广泛的协议,无论是西门子S7协议.三菱MC协议或者是欧姆龙的Fins-TCP协议等,都是TCP通信协议的典型应用.很多人在上位机面试时,都 ...
- springMvc接口开发--对访问的restful api接口进行拦截实现功能扩展
1.视频参加Spring Security开发安全的REST服务\PART1\PART1 3-7 使用切片拦截REST服务三通it学院-www.santongit.com-.mp4 讲的比较的经典,后 ...
- Python3-pymysql模块-数据库操作之MySQL
博客转载 http://www.cnblogs.com/alex3714/articles/5950372.html 代码示例 import pymysql conn = None cursor = ...