4. 彤哥说netty系列之Java NIO实现群聊(自己跟自己聊上瘾了),netty实现

你好,我是彤哥,本篇是netty系列的第四篇。

欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识。

简介

上一章我们一起学习了Java中的BIO/NIO/AIO的故事,本章将带着大家一起使用纯纯的NIO实现一个越聊越上瘾的“群聊系统”。

业务逻辑分析

首先,我们先来分析一下群聊的功能点:

(1)加入群聊,并通知其他人;

(2)发言,并通知其他人;

(3)退出群聊,并通知其他人;

一个简单的群聊系统差不多这三个功能足够了,为了方便记录用户信息,当用户加入群聊的时候自动给他分配一个用户ID。

业务实现

上代码:

// 这是一个内部类

private static class ChatHolder {

// 我们只用了一个线程,用普通的HashMap也可以

static final Map USER_MAP = new ConcurrentHashMap<>();

/**

* 加入群聊

* @param socketChannel

*/

static void join(SocketChannel socketChannel) {

// 有人加入就给他分配一个id,本文来源于公从号“彤哥读源码”

String userId = "用户"+ ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE);

send(socketChannel, "您的id为:" + userId + "\n\r");

for (SocketChannel channel : USER_MAP.keySet()) {

send(channel, userId + " 加入了群聊" + "\n\r");

}

// 将当前用户加入到map中

USER_MAP.put(socketChannel, userId);

}

/**

* 退出群聊

* @param socketChannel

*/

static void quit(SocketChannel socketChannel) {

String userId = USER_MAP.get(socketChannel);

send(socketChannel, "您退出了群聊" + "\n\r");

USER_MAP.remove(socketChannel);

for (SocketChannel channel : USER_MAP.keySet()) {

if (channel != socketChannel) {

send(channel, userId + " 退出了群聊" + "\n\r");

}

}

}

/**

* 扩散说话的内容

* @param socketChannel

* @param content

*/

public static void propagate(SocketChannel socketChannel, String content) {

String userId = USER_MAP.get(socketChannel);

for (SocketChannel channel : USER_MAP.keySet()) {

if (channel != socketChannel) {

send(channel, userId + ": " + content + "\n\r");

}

}

}

/**

* 发送消息

* @param socketChannel

* @param msg

*/

static void send(SocketChannel socketChannel, String msg) {

try {

ByteBuffer writeBuffer = ByteBuffer.allocate(1024);

writeBuffer.put(msg.getBytes());

writeBuffer.flip();

socketChannel.write(writeBuffer);

} catch (Exception e) {

e.printStackTrace();

}

}

}

服务端代码

服务端代码直接使用上一章NIO的实现,只不过这里要把上面实现的业务逻辑适时地插入到相应的事件中。

(1)accept事件,即连接建立的时候,说明加入了群聊;

(2)read事件,即读取数据的时候,说明有人说话了;

(3)连接断开的时候,说明退出了群聊;

OK,直接上代码,为了与上一章的代码作区分,彤哥特意加入了一些标记:

public class ChatServer {

public static void main(String[] args) throws IOException {

Selector selector = Selector.open();

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.bind(new InetSocketAddress(8080));

serverSocketChannel.configureBlocking(false);

// 将accept事件绑定到selector上

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {

// 阻塞在select上

selector.select();

Set selectionKeys = selector.selectedKeys();

// 遍历selectKeys

Iterator iterator = selectionKeys.iterator();

while (iterator.hasNext()) {

SelectionKey selectionKey = iterator.next();

// 如果是accept事件

if (selectionKey.isAcceptable()) {

ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();

SocketChannel socketChannel = ssc.accept();

System.out.println("accept new conn: " + socketChannel.getRemoteAddress());

socketChannel.configureBlocking(false);

socketChannel.register(selector, SelectionKey.OP_READ);

// 加入群聊,本文来源于公从号“彤哥读源码”

ChatHolder.join(socketChannel);

} else if (selectionKey.isReadable()) {

// 如果是读取事件

SocketChannel socketChannel = (SocketChannel) selectionKey.channel();

ByteBuffer buffer = ByteBuffer.allocate(1024);

// 将数据读入到buffer中

int length = socketChannel.read(buffer);

if (length > 0) {

buffer.flip();

byte[] bytes = new byte[buffer.remaining()];

// 将数据读入到byte数组中

buffer.get(bytes);

// 换行符会跟着消息一起传过来

String content = new String(bytes, "UTF-8").replace("\r\n", "");

if (content.equalsIgnoreCase("quit")) {

// 退出群聊,本文来源于公从号“彤哥读源码”

ChatHolder.quit(socketChannel);

selectionKey.cancel();

socketChannel.close();

} else {

// 扩散,本文来源于公从号“彤哥读源码”

ChatHolder.propagate(socketChannel, content);

}

}

}

iterator.remove();

}

}

}

}

测试

打开四个XSHELL客户端,分别连接telnet 127.0.0.1 8080,然后就可以开始群聊了。

彤哥发现,自己跟自己聊天也是会上瘾的,完全停不下来,不行了,我再去自聊一会儿^^

总结

本文彤哥跟着大家一起实现了“群聊系统”,去掉注释也就100行左右的代码,是不是非常简单?这就是NIO网络编程的魅力,我发现写网络编程也上瘾了^^

问题

这两章我们都没有用NIO实现客户端,你知道怎么实现吗?

提示:服务端需要监听accept事件,所以需要有一个ServerSocketChannel,而客户端是直接去连服务器了,所以直接用SocketChannel就可以了,一个SocketChannel就相当于一个Connection。

最后,也欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识。

相关文章暂无相关文章

java nio netty 教程,4. 彤哥说netty系列之Java NIO实现群聊(自己跟自己聊上瘾了),netty实现...相关推荐

  1. java channel源码_彤哥说netty系列之Java NIO核心组件之Channel

    你好,我是彤哥,本篇是netty系列的第五篇. 欢迎来我的工从号彤哥读源码系统地学习源码&架构的知识. 简介 上一章我们一起学习了如何使用Java原生NIO实现群聊系统,这章我们一起来看看Ja ...

  2. java channel源码_5. 彤哥说netty系列之Java NIO核心组件之Channel

    你好,我是彤哥,本篇是netty系列的第五篇. 简介 上一章我们一起学习了如何使用Java原生NIO实现群聊系统,这章我们一起来看看Java NIO的核心组件之一--Channel. 思维转变 首先, ...

  3. java 仿qq庅,4. 彤哥说netty系列之Java NIO实现群聊(自己跟自己聊上瘾了)

    你好,我是彤哥,本篇是netty系列的第四篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 上一章我们一起学习了Java中的BIO/NIO/AIO的故事,本章将带着大家一起使 ...

  4. java netty教程_明哥教学 - Netty简单入门教程

    作为一个正在Java路上摸爬滚打的小菜鸡,之前在项目中也用过Netty,也因为Netty报名阿里的中间件大赛,但终究功力太浅,最终不了了之,最近工作中又遇到了Netty的小姐妹Mina.此时楼主觉得N ...

  5. java se13安装教程_在Linux发行版中安装Java 13/OpenJDK 13的方法

    本文介绍在Linux发行版Ubuntu 18.04/16.04.Debian 10/9.CentOS 7/8.Fedora 31/30/29中安装Java 13/OpenJDK 13.Java SE ...

  6. java转安卓快吗_安卓Kotlin开发系列之Java快速转Kotlin

    原标题:安卓Kotlin开发系列之Java快速转Kotlin 自从Kotlin被宣布为Android开发语言的官方支持后,如今可谓是火的一塌糊涂,作为一名Android程序员,如何快速爬坑?今天为大家 ...

  7. 我的世界java版按键教程视频_我的世界(电脑Java版)execute指令教程

    注:该教程基于Java V1.16.3   通常可以兼容1.13+的版本 1.9-1.12可能会有不兼容,出现问题可以在评论区提问.如果1.12及以下的玩家较多,以后会专门出一个针对1.12及以下的教 ...

  8. java后端开发教程_【后端开发】详细讲解JAVA中方法重载概念——简单易懂

    1.什么方法重载? 方法的重载指的是方法名一样,但是参数类型不一样 1.1.attack方法重载 有一种英雄,叫做物理攻击英雄 ADHero,为ADHero 提供三种方法. public void a ...

  9. java 只有日期的类_【你不知道的事系列】Java中处理日期的类

    Java中提供了一系列用于处理日期.时间的类,包括创建日期,时间对象,获取系统当前日期,时间等操作 Date类: 位于java.util.Date,从JDK1.0起就存在了,但现在它的大部分构造器,方 ...

最新文章

  1. 【响应式Web前端设计】设置图片间隙为0
  2. 自动生成网络拓扑图开源_为视频自动生成字幕,一款神奇的开源工具!
  3. mysql 数据库还原 不齐_请教mysql数据库还原问题。
  4. 【渝粤教育】 广东开放大学21秋期末考试管理学基础10241k2
  5. 百度贴吧 2017 前贴子无法访问;网易腾讯游戏获批;苹果反垄断案败诉 | 极客头条...
  6. 为什么互联网公司需要测试人员?
  7. Android MVP和Dagger2
  8. 目标检测(十三)--MultiPathNet
  9. Atitit 项目沟通管理 艾提拉总结 目录 1. 项目中沟通对象 2 1.1. 主要为项目干系人 产品部门 运营部门组员等 2 1.2. 适当越级沟通, 与高层直接沟通 3 2. 沟通频率 3
  10. 梨花风起正清明,清明习俗知多少?
  11. 流光容易把人抛,红了樱桃,绿了芭蕉
  12. php创建微信公众号管理系统-序言
  13. 如果这篇文章说不清epoll的本质,那就过来掐死我吧
  14. Groory语言关于省略的知识点
  15. Android 8.1 DisplayPowerController(五) 自动调节亮度(2)——算法
  16. 攻防世界 —— Crypto新手练习区7题(不仅仅是Morse)题解
  17. 腾讯云硬盘挂载宝塔命令
  18. 服务器端和客户端互发消息,Socket编程实现简单的服务器与客户端互发消息
  19. slf4j简单介绍(2)-使用
  20. java反斜杠_如何在字符串中使用反斜杠(\)?

热门文章

  1. 【CSS】在圆上设置文字
  2. 关于M1版Macbook Pro 安装JDK 方法
  3. 第八章 对立统一——异步时钟同步化
  4. ViewPager+Fragment+ViewPager+Fragment
  5. IoT物联网平台如何实现大规模设备的高效控制?
  6. 如果你来投票决定百度的生死,你会如何抉择?
  7. 宁选“范跑跑”,不要“郭跳跳”
  8. 2007年十大最帅网站CEO
  9. java虚拟机学习笔记2
  10. 基于Bootstrap的后台管理系统模板。AceAdmin停更前最后的两个版本