netty实现群聊,点击查看

需求:在群聊基础上,增加私聊功能

Server

package com.lian.groupprivatechat;import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.GenericFutureListener;public class Server {//监听端口private Integer port;public Server(Integer port) {this.port = port;}//编写run方法,处理客户端的请求public void run() throws InterruptedException {//创建两个线程组NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);NioEventLoopGroup workerGroup = new NioEventLoopGroup();try {//创建workerGroup启动类ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG,128).childOption(ChannelOption.SO_KEEPALIVE,true).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();//向pipeline里加入解码器pipeline.addLast("decoder",new StringDecoder());向pipeline里加入编码器pipeline.addLast("encoder",new StringEncoder());向pipeline里加入自定义业务处理器pipeline.addLast(new ServerHandler());}});System.out.println("netty server start");//绑定端口ChannelFuture channelFuture = serverBootstrap.bind(port).sync();//添加监听器channelFuture.addListener(new GenericFutureListener<Future<? super Void>>() {@Overridepublic void operationComplete(Future<? super Void> future) throws Exception {if (channelFuture.isSuccess()){System.out.println("server is startting...");}else if (channelFuture.isDone()){System.out.println("server started success...");}}});//监听关闭通道channelFuture.channel().closeFuture().sync();//添加监听器channelFuture.addListener(new GenericFutureListener<Future<? super Void>>() {@Overridepublic void operationComplete(Future<? super Void> future) throws Exception {if (channelFuture.isCancelled()){System.out.println("server is stopping...");}else if (channelFuture.isCancellable()){System.out.println("server was stopped...");}}});}finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {new Server(9999).run();}
}

ServerHandler

package com.lian.groupprivatechat;import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;public class ServerHandler extends SimpleChannelInboundHandler<String> {/*** 定义一个channle 组,管理所有的channel* GlobalEventExecutor.INSTANCE) 是全局的事件执行器,是一个单例*/private static DefaultChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);/*** 为了实现私聊功能,这里key存储用户的唯一标识,* 客户端的端口号* 当然 这个集合也需要自己去维护 用户的上下线 不能像 ChannelGroup那样自己去维护*/private static Map<String, Channel> map = new HashMap<>();//创建日期SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");/*** 服务器读取客户端的数据* @param ctx* @param msg* @throws Exception*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {//获取当前通道Channel channel = ctx.channel();/*** 私聊,这里简单判断 如果内容里边包含#那么就是私聊*/if (msg.contains("#")){String id = msg.split("#")[0];String body = msg.split("#")[1];Channel userChannel = map.get(id);System.out.println("userChannel: "+userChannel);//求出远程地址的 key值9609  /127.0.0.1:9609String key = channel.remoteAddress().toString().split(":")[1];userChannel.writeAndFlush(sdf.format(new Date())+"\n client "+key+" say : "+body);}//判断当前消息是不是自己发送的,循环遍历channelGroup组中的channelchannelGroup.forEach(ch->{//如果循环遍历的不是当前的channel,就转发消息给其他客户if (channel != ch){ch.writeAndFlush("client"+channel.remoteAddress()+" send message "+msg+"\n");}else {//如果循环遍历到的是当前channel,就回显自己发送的消息给自己ch.writeAndFlush("self send message "+msg+"\n");}});}/*** handlerAdded 表示连接建立,一旦连接,第一个被执行* 将当前channel 加入到  channelGroup* 建立连接以后第一个调用的方法*/@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();/*** 将该客户加入聊天的信息推送给其它在线的客户端* 该方法会将 channelGroup 中所有的channel 遍历,并发送 消息,* 我们不需要自己遍历*/channelGroup.writeAndFlush("client: "+channel.remoteAddress()+" join chatting"+" time is "+sdf.format(new Date())+"\n");channelGroup.add(channel);// /127.0.0.1:9394String key = channel.remoteAddress().toString().split(":")[1];map.put(key, channel);}/*** 表示channel 处于活动状态, 提示 xx上线* @param ctx* @throws Exception*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();System.out.println(channel.remoteAddress()+" on-line...");}/*** 表示channel 处于不活动状态, 提示 xx离线了* @param ctx* @throws Exception*/@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();System.out.println(channel.remoteAddress()+" off-line...");//下线移除String key = channel.remoteAddress().toString().split(":")[1];map.remove(key);}/*** 断开连接,将xx客户离开的消息推送给当前在线的其他客户,有人下线了通知到其他在线的人*/@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();channelGroup.writeAndFlush("client "+channel.remoteAddress()+" leaving\n");System.out.println("channelGroup size"+channelGroup.size());System.out.println("map size: "+map.size());}/*** 捕获异常* @param ctx* @param cause* @throws Exception*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {//出现异常关闭通道ctx.channel().close();}
}

Client

package com.lian.groupprivatechat;import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;import java.util.Scanner;public class Client {private final String host;private final Integer port;public Client(String host, Integer port) {this.host = host;this.port = port;}public void run() throws Exception {NioEventLoopGroup clientEventLoopGroup = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(clientEventLoopGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("decoder",new StringDecoder());pipeline.addLast("encoder",new StringEncoder());pipeline.addLast(new ClientHandler());}});//绑定主机和端口ChannelFuture channelFuture = bootstrap.connect(host,port).sync();//添加监听器channelFuture.addListener(new GenericFutureListener<Future<? super Void>>() {@Overridepublic void operationComplete(Future<? super Void> future) throws Exception {if (channelFuture.isSuccess()){System.out.println("client is startting...");}else if (channelFuture.isDone()){System.out.println("client is start success...");}}});Channel channel = channelFuture.channel();System.out.println("----------"+channel.localAddress()+"-----------");//创建扫描器Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()){String msg = scanner.nextLine();//将控制台上的数据写入到channel中channel.writeAndFlush(msg+"\r\n");}//监听关闭通道channelFuture.channel().closeFuture().sync();scanner.close();}finally {clientEventLoopGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {new Client("127.0.0.1",9999).run();}
}

ClientHandler

package com.lian.groupprivatechat;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;public class ClientHandler extends SimpleChannelInboundHandler<String> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {System.out.println(msg.trim());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.channel().close();}
}

测试

----------/127.0.0.1:13983-----------
client�� /127.0.0.1:14023 join chatting time is 2021-04-12 20:23:25
2021-04-12 20:23:35client 14023 say : you are a son//id # message
14023 # i am your parent
self send message
----------/127.0.0.1:14023-----------
13983 # you are a son
client/127.0.0.1:13983 send message 2021-04-12 20:24:00client 13983 say : i am your parent

Netty教程06:netty实现群聊私聊相关推荐

  1. Java网络编程:TCP实现群聊私聊代码

    Java网络编程:TCP实现群聊&私聊代码 和上一篇博客差不多,只不过是在群里的基础之上增加了私聊的功能,我们约定,私聊格式为:@xxx:msg 如何实现私聊呢,加入客户端c给服务器发送消息, ...

  2. Java WebSocket实现网络聊天室(群聊+私聊)

    WebChat聊天室 2018.02.26 源码地址早就贴了呀, 留邮箱不如自己下载 项目地址: https://github.com/Amayadream/WebChat 2017.01.11更新 ...

  3. 群聊私聊天建群社交即时通讯H5系统开发

    群聊私聊天建群社交即时通讯H5系统开发 前端功能: 聊天.通讯录.动态.发现.我.多国语言.私聊.群聊.创建群聊(设置免费.收费).发布动态.发信息(图片.文字.红包.不支持语言).我的余额(后台添加 ...

  4. netty自定义handler分别支持群聊和单聊

    消息实体类 public class WsMessage {/** 消息id */private String id;/** 消息发送类型 */private Integer code;/** 发送人 ...

  5. (六)Netty网络编程应用实例-群聊系统

    实例要求: 编写一个NIO群聊系统,实现服务器端和客户端之间的数据简单通讯(非阻塞) 实现多人群聊 服务器端:可以监测用户上线,离线,并实现消息转发功能 客户端:通过channel可以无阻塞发送消息给 ...

  6. Netty聊天系统(4)群聊功能实现

    7 群聊功能的实现 7.1 群聊的创建 创建一个创建群聊请求的实体类,依然是继承Packet,因为要通过我们的协议进行编解码 服务器端创建一个处理创建群聊请求的Handler,并实现其中的逻辑 创建一 ...

  7. Swoole实现基于WebSocket的群聊私聊

    本文属于入门级文章,大佬们可以绕过啦.如题,本文会实现一个基于Swoole的websocket聊天室(可以群聊,也可以私聊,具体还需要看数据结构的设计). 搭建Swoole环境 通过包管理工具 # 安 ...

  8. JAVA 网络聊天程序设计与实现(附关键代码) 可群聊私聊发送图片

    1 需求分析 经分析,本程序是一个C/S结构,使用TCP协议实现聊天功能,需要实现的功能有如下几点. 本程序需要有客户端以及服务器端. 客户端应有良好的交互界面,服务器端应有转发客户端发来的消息和临时 ...

  9. java多人聊天室实现(可群聊私聊/添加好友/发送文件)

    一.功能介绍 本程序基于websocket实现,程序主要借鉴参考 https://www.cnblogs.com/csu-lmw/p/10981374.html,并在原程序的基本框架下扩充了添加好友以 ...

最新文章

  1. 用python正确的获取文件最后被修改的时间
  2. 节点服务器虚拟网络,虚拟网络功能节点放置研究
  3. Uart接口的详细解释
  4. cvs update 的输出标志/update常用几个参
  5. 十三、axios框架学习
  6. 《C++ Primer》第五版课后习题解答_第二章(1)(01-08)
  7. Membership、MembershipUser和Roles类
  8. 产品经理-思维导图梳理功能
  9. python 批量打开网页并截图_如何实现批量截取整个网页完整长截图,批量将网页保存成图片web2pic/webshot/screencapture/html2picture...
  10. 常用电子元器件基本知识整理
  11. Python电商数据分析实战案例
  12. npoi合并取消合并单元格
  13. Android TV开发
  14. 【目标检测】《DINO: DETR with Improved DeNoising Anchor Boxes for End-to-End Object Detection》论文阅读笔记
  15. 白胡子不杀黑胡子的真正原因
  16. Intel汇编-无符号整数的乘法操作
  17. 华为电脑怎么录屏?分享你两个好方法
  18. MySQL 计算环比(同比类似)
  19. 省赛选拔-A 警察抓小偷
  20. 计蒜客python刷题笔记

热门文章

  1. 推荐23个Python爬虫开源项目代码:爬取微信、淘宝、豆瓣、知乎、微博等
  2. JSP getparameter方法
  3. 集“XXXXX”或它的某一个依赖项。生成此程序集的运行时比当前加载的运行时新,无法加载此程序集。”
  4. rmp mysql_整理linux 下rmp格式Mysql安装
  5. 洛谷 P1346 电车 dijkstra
  6. linux中测试带宽的命令,【linux】测试网络带宽
  7. C#的Session创建和使用
  8. MySql5.7下载、安装、配置详解。(win10版本)
  9. 爱立信CEO卫翰思否认将被思科收购
  10. jvm gc回收器 和 jvm 数据结构