基于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 ...
随机推荐
- pip 通过pqi切换源到国内镜像
pip install pqipqi lspqi use aliyun # pqi use tuna 清华
- C# 元组
Tuple<,); Console.WriteLine(t.Item1); Console.WriteLine(t.Item2); C#7 可以使用圆括号声明一个元组: (); Console. ...
- Different Integers
牛客一 J题 树状数组 题目描述 Given a sequence of integers a1, a2, ..., an and q pairs of integers (l1, r1), (l2, ...
- 磁盘处于脱机状态"解决办法
由于管理员设置的策略,该磁盘处于脱机状态"解决办法 1.运行:cmd 2.输入:DISKPART.exe 3.DISKPART> san 4.DISKPART> san poli ...
- 牛客-Forsaken的数列(Treap)
题目传送门 sol:第一次看题还真信了是用线段树来做,但是没什么想法,看了题解发现是我不会的Treap,然后花了几天时间学习了一下并补掉题目 无旋Treap #include <bits/std ...
- 2)echo count(strlen("test")) 的输出为____
结果是 1: 因为count测的是单元的数目,你的一个数组就是一个单元,所以 他的结果就是1 题目出处: https://www.nowcoder.com/test/question/done?ti ...
- 利用Python进行图片发送与接收的两种方法---包含客户端和服务器端代码
第一种方法 opencv.requests.flask 此方法比较耗费时间 600毫秒左右 客户端代码 #coding:utf-8 import cv2 import json import requ ...
- Redis为什么会比MySQL快?
1.Redis是基于内存存储的,MySQL是基于磁盘存储的 2.Redis存储的是k-v格式的数据.时间复杂度是O(1),常数阶,而MySQL引擎的底层实现是B+Tree,时间复杂度是O(logn), ...
- smtp 邮件传输协议 qq版实现
qq: telnet smtp.qq.com 587 (qq邮箱说明:http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28& ...
- java面试题 -- 基础
1.抽象和封装的不同点抽象和封装是互补的概念.一方面,抽象关注对象的行为.另一方面,封装关注对象行为的细节.一般是通过隐藏对象内部状态信息做到封装,因此,封装可以看成是用来提供抽象的一种策略.2.重载 ...