关键抽象

  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 实例之多人聊天的更多相关文章

  1. Java NIO示例:多人网络聊天室

    一个多客户端聊天室,支持多客户端聊天,有如下功能: 功能1: 客户端通过Java NIO连接到服务端,支持多客户端的连接 功能2:客户端初次连接时,服务端提示输入昵称,如果昵称已经有人使用,提示重新输 ...

  2. java swing+socket实现多人聊天程序

    swing+socket实现多人聊天程序 1.准备工作 先看效果: 客户端项目结构图: 服务端项目结构图: 2.运行原理 服务端 先开一个线程serverListerner,线程中开启一个Server ...

  3. Java使用socket实现两人聊天对话

    import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; /* ...

  4. Java NIO 聊天室实例

    最近写了个Java NIO聊天室聊天的程序,NIO学习起来比较困难的,我的代码能给大家起到一个抛砖引玉的作用! 服务端: package test.javanio; /** * @author * @ ...

  5. Java NIO实战之聊天室

    在工作之余花了两个星期看完了<Java NIO>.整体来说这本书把NIO写的非常具体,没有过多的废话,讲的都是重点,仅仅是翻译的中文版看的确实吃力.英文水平太低也没办法,总算也坚持看完了. ...

  6. Java nio socket与as3 socket(粘包解码)连接的应用实例

    对Java nio socket与as3 socket连接的简单应用 <ignore_js_op>Java nio socket与as3 socket连接的应用实例.rar (9.61 K ...

  7. Java NIO原理及实例

    Java NIO是在jdk1.4开始使用的,它既可以说成“新I/O”,也可以说成非阻塞式I/O.下面是java NIO的工作原理: 1. 由一个专门的线程来处理所有的 IO 事件,并负责分发. 2. ...

  8. java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端

    java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端 启动界面如下图: 首先启动服务器: 客户端登陆,登陆成功后为: 默认发送是全部用户,是多人发送. 当在边列 ...

  9. 多人聊天室(Java)

    第1部分 TCP和UDP TCP:是一种可靠地传输协议,是把消息按一个个小包传递并确认消息接收成功和正确才发送下一个包,速度相对于UDP慢,但是信息准确安全:常用于一般不要求速度和需要准确发送消息的场 ...

随机推荐

  1. java关键字volatile用法详解

    volatile关键字想必大家都不陌生,在java 5之前有着挺大的争议,在java 5之后才逐渐被大家接受,同时作为java的关键字之一,其作用自然是不可小觑的,要知道它是java.util.con ...

  2. ODEINT 求解常微分方程(2)

    import numpy as np from scipy.integrate import odeint import matplotlib.pyplot as plt # function tha ...

  3. 菜鸟教程—SQL测验

    SQL 测验 结果:17/3 1. SQL 指的是? 你的回答: Structured Question Language 回答错误! 正确答案:Structured Query Language 2 ...

  4. Spting:基于注解的组件化管理

    @Component,@Controller(控制层),@Service(业务层),@Repository(持久层) 以上四个注解的功能完全相同,不过在实际开发中,要在不同功能的类上加上响应的注解 1 ...

  5. [转] VMware中的Ubuntu无法通过桥接方式上网

    遇到的问题:主机可以上网(使用了代理),VMware设置为桥接方式连网.在主机中可以ping通虚拟机,在虚拟机中也可以ping通主机,可是在虚拟机中始终连接不了因特网. 感谢刘洋同学的博文,“在桥接模 ...

  6. 2019-02-02 Python学习——生成器杨辉三角,迭代器与可迭代对象的区别

    练习 杨辉三角定义如下: 1 / \ 1 1 / \ / \ 1 2 1 / \ / \ / \ 1 3 3 1 / \ / \ / \ / \ 1 4 6 4 1 / \ / \ / \ / \ / ...

  7. Arduino + RFID 读取 IC 卡 Arduino uno中获得RFID的UID 并通过串口转发RFID卡号

    RFID简介:射频识别即RFID(Radio Frequency IDentification)技术,又称无线射频识别,是一种通信技术,可通过无线电讯号识别特定目标并读写相关数据,而无需识别系统与特定 ...

  8. 数据库语言sql

    数据库语言SQL SQL的形式 交互式SQL 一般DBMS都提供联机交互工具 用户可直接键入SQL命令对数据库进行操作 由DBMS来进行解释 嵌入式SQL 能将SQL语句嵌入到高级语言(宿主语言) 使 ...

  9. TCP 重置攻击的工作原理

    原文链接:https://fuckcloudnative.io/posts/deploy-k3s-cross-public-cloud/ TCP 重置攻击 是使用一个单一的数据包来执行的,只有几个字节 ...

  10. 多语言工作者の十日冲刺<6/10>

    这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺--第六天(05.05) 作业正文 ...