基于netty的群聊
学了一段时间的netty知识,现在通过这个基于console的程序来对netty的相关接口做个简单的应用。
准备
依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.44.Final</version>
</dependency>
代码实现
我们都知道,一个典型的netty程序绝大部分使基于以下三部曲来走的;
- server/client 启动类
- xxxInitializer (implements ChannelInitializer<?> )
- xxxChannelHandler (implememts SimpleChannelInboundHandler<?>)
按照以上的三部曲思路,就可以实现自己的网络程序了。
Server端实现
server启动类
public class MyChatServer {
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new MyChatServerInitializeor());
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
serverChannelInitializer
public class MyChatServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// 粘包、粘包处理器
pipeline.addLast("DelimiterBasedFrameDecoder", new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()));
pipeline.addLast("StringDecoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("StringEncoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new MyServerChannelHandler());
}
}
serverChannelHandler
public class MyServerChannelHandler extends SimpleChannelInboundHandler<String> {
/**
* 保存channel对象
*/
private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
private static final String DATE_PARTTEN = "yyyy-MM-dd HH:mm:ss:SSS";
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel channel = ctx.channel();
channelGroup.forEach(ch -> {
// 当前遍历的channel不是发送msg的channel对象。则向其他客户端广播
if (channel != ch) {
ch.writeAndFlush(channel.remoteAddress() + ", 发送的消息" + msg + "\n");
} else {
ch.writeAndFlush("[自己] " + msg + " \n");
}
});
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress() + " 上线了!");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress() + " 离开了!");
}
/**
* 客户端链接建立的时候调用
* @param ctx
* @throws Exception
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
//super.handlerAdded(ctx);
// 服务端与客户端建立
Channel channel = ctx.channel();
// 向其他链接的客户端发送广播信息
SocketAddress socketAddress = channel.remoteAddress();
String date = DateTimeFormatter.ofPattern(DATE_PARTTEN).format(LocalDateTime.now());
// 向channelGroup中的每一个channel对象发送一个消息
channelGroup.writeAndFlush(date + " [服务器] - " + socketAddress + " 加入 \n");
// 保存该客户端链接
channelGroup.add(channel);
}
/**
* 链接断开
* @param ctx
* @throws Exception
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
String date = DateTimeFormatter.ofPattern(DATE_PARTTEN).format(LocalDateTime.now());
channelGroup.writeAndFlush(date + " [服务器] - " + channel.remoteAddress() + " 离开 \n");
}
/**
* 客户端注册进来
* @param ctx
* @throws Exception
*/
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
super.channelRegistered(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
super.channelUnregistered(ctx);
}
}
client 端实现
client启动类
public class MyChatClient {
public static void main(String[] args) {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.handler(new MyClientChannelInitializor());
ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync();
Channel channel = channelFuture.channel();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
for (; ; ) {
channel.writeAndFlush(bufferedReader.readLine() + "\r\n");
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
}
clientChannelInitializer
public class MyClientChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("DelimiterBasedFrameDecoder", new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()));
pipeline.addLast("StringDecoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("StringEncoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new MyChatClientChannelHandler());
}
}
clientChannelHandler
public class MyChatClientChannelHandler extends SimpleChannelInboundHandler<String> {
// 直接打印服务端返回的消息
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg);
}
}
基于netty的群聊的更多相关文章
- netty实现群聊功能
[概述] 实现一个网络群聊工具.参与聊天的客户端消息是通过服务端进行广播的. 主要由两块组成:聊天服务器端(ChatServer)和聊天客户端(ChatClient). 聊天服务器(ChatServe ...
- 基于netty实现单聊、群聊功能
学习资料 https://juejin.im/book/5b4bc28bf265da0f60130116/section/5b6a1a9cf265da0f87595521 收获: 转载 1. Nett ...
- Android基于socket的群聊程序
在网上看了好多,但是感觉不是太简单就是只能单独聊,所以就自己写了个可以群聊的,直接上代码了 一.服务器端 这里用的MyEclipse作为服务器端 MyServerScoket.java package ...
- 一例完整的websocket实现群聊demo
前言 业余我都会花一些时间在tcp.http和websocket等领域的学习,现在觉得有点收获,所以把一个基于websocket的群聊功能的例子提供给大家玩玩.当然这是一个很完整的例子,包括webso ...
- 一套高可用、易伸缩、高并发的IM群聊架构方案设计实践
本文原题为“一套高可用群聊消息系统实现”,由作者“于雨氏”授权整理和发布,内容有些许改动,作者博客地址:alexstocks.github.io.应作者要求,如需转载,请联系作者获得授权. 一.引言 ...
- 基于itchat的微信群聊小助手基础开发(一)
前段时间由于要管理微信群,基于itchat开发了一个简单的微信机器人 主要功能有: 图灵机器人功能 群聊昵称格式修改提示 消息防撤回功能 斗图功能 要开发一个基于itchat的最基本的聊天机器人,在g ...
- 基于Kurento的WebRTC移动视频群聊技术方案
说在前面的话:视频实时群聊天有三种架构: Mesh架构:终端之间互相连接,没有中心服务器,产生的问题,每个终端都要连接n-1个终端,每个终端的编码和网络压力都很大.群聊人数N不可能太大. Router ...
- 基于ejabberd简单实现xmpp群聊离线消息
首先,xmpp服务器是基于ejabberd.离线消息模块是mod_interact,原地址地址:https://github.com/adamvduke/mod_interact: 修改后实现群聊离线 ...
- Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)
一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(en ...
随机推荐
- 编译原理_P1003
1. 语法分析 1.1 上下文无关文法的定义 ---- 正规式能定义一下简单的语言,能表示给定结构的固定次数的重复或者没有指定次数的重复 例如:a(ba)5,a(ba)* ---- 正规式不能用于描 ...
- s01字符串---蓝桥杯
问题描述 s01串初始为"0" 按以下方式变换 0变1,1变01 输入格式 1个整数(0~19) 输出格式 n次变换后s01串 样例输入 3 样例输出 101 数据规模和约定 0~ ...
- [USACO09DEC]晕牛Dizzy Cows (拓扑排序)
https://www.luogu.org/problem/P2017 题目背景 Hzwer 神犇最近又征服了一个国家,然后接下来却也遇见了一个难题. 题目描述 The cows have taken ...
- sql server 重命名表名,字段名
重命名表名: exec sp_rename 'oldName','newName'; 重命名字段名: exec sp_rename 'tableName.[oldName]','newName','c ...
- IPC之——消息队列
消息队列作用: 可以用于两个没有联系的进程间通信,创建一个消息队列类似于打开了一个文件,两个不同的进程都可以进行操作 消息队列之函数介绍: 头文件:<sys/type.h> <sys ...
- python en(de)code
python爬虫 代码写挺长的,也是边学边写,但一直搞不清楚python的encode(编码)和decode(解码).以下是我的探究之路. 一.当然先看官方文档 地址如下 里面提到encode函数'R ...
- 3dmax2019卸载/安装失败/如何彻底卸载清除干净3dmax2019注册表和文件的方法
3dmax2019提示安装未完成,某些产品无法安装该怎样解决呢?一些朋友在win7或者win10系统下安装3dmax2019失败提示3dmax2019安装未完成,某些产品无法安装,也有时候想重新安装3 ...
- 牛客-小y的盒子
题目传送门 -------------------稍加观察就会发现,4n - 1就是题目要的答案.至于为什么,看官方的题解.不过这个n非常的大,用正常快速幂解决不了.这道题我学到的就是解决幂非常大的情 ...
- B-Tree索引
翻译自http://dev.mysql.com/doc/refman/5.6/en/index-btree-hash.html 理解B-Tree和Hash的数据结构能够帮助我们预测不同存储引擎下的查询 ...
- 转:Zabbix 监控sqlserver
一:Zabbix监控sqlserver 方法一: 1.思路整理 1.在zabbix server上安装Freetds.unixODBC.unixODBC-devel使其能够访问SQL Server数据 ...