关键抽象

  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. 洛谷 P1115 最大子序和

    **原题链接** ##题目描述   给出一段序列,选出其中连续且非空的一段使得这段和最大.     **解法**:       1.暴力枚举 时间:O(n^3)       2.简单优化 时间:O(n ...

  2. iOS-自定义 UITabBarController

    先来回顾一下UITabBarController ( 稍微详细的在在http://blog.csdn.net/yang198907/article/details/49807011) 伴随UITabB ...

  3. mysql 大表mysqldump迁移方案

    场景 一张历史表product_history 500万数据,凌晨的才会将正式表的数据迁移到历史表,此次需求将历史表迁移到一个更便宜的数据库实例进行存储. 条件 1.此表不是实时写,凌晨才会更新 2. ...

  4. App接口设计之token的php实现

    为了保证移动端和服务端数据传输相对安全,需要对接口进行加密传输. 一.ttoken的设计目的:  因为APP端没有和PC端一样的session机制,所以无法判断用户是否登陆,以及无法保持用户状态,所以 ...

  5. python数据预处理

    缺失值处理 import pandas as pda import numpy as npy import matplotlib.pylab as pyl # data=pda.read_excel( ...

  6. Web前端 -- Webpack

    一.Webpack Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源. 二.Webpack安装 1.全局安装 npm i ...

  7. Shiro实战教程-刘志敏-专题视频课程

    Shiro实战教程-62人已学习 课程介绍        本教程只介绍基本的 Shiro 使用,不会过多分析源码等,重在使用. 适用人群: 1.了解基于Servlet进行Web应用开发 2.了解Spr ...

  8. idea 2018版/2019版的破解

    idea 2019版破解的穿越隧道:https://www.jianshu.com/p/09c9afae9a05 idea 2018版破解的穿越隧道:https://www.jianshu.com/p ...

  9. Day10-微信小程序实战-交友小程序-实现删除好友信息与子父组件间通信

    回顾:上一次已经把消息的布局以及样式做好了 效果图: 在removeList.js文件中,messageId就是发起这个消息的用户了 先查看一下自定义组件的生命周期 https://developer ...

  10. 入门大数据---通过Flume、Sqoop分析日志

    一.Flume安装 参考:Flume 简介及基本使用 二.Sqoop安装 参考:Sqoop简介与安装 三.Flume和Sqoop结合使用案例 日志分析系统整体架构图: 3.1配置nginx环境 请参考 ...