学了一段时间的netty知识,现在通过这个基于console的程序来对netty的相关接口做个简单的应用。

准备

依赖

<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.44.Final</version>
</dependency>

代码实现

我们都知道,一个典型的netty程序绝大部分使基于以下三部曲来走的;

  1. server/client 启动类
  2. xxxInitializer (implements ChannelInitializer<?> )
  3. 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的群聊的更多相关文章

  1. netty实现群聊功能

    [概述] 实现一个网络群聊工具.参与聊天的客户端消息是通过服务端进行广播的. 主要由两块组成:聊天服务器端(ChatServer)和聊天客户端(ChatClient). 聊天服务器(ChatServe ...

  2. 基于netty实现单聊、群聊功能

    学习资料 https://juejin.im/book/5b4bc28bf265da0f60130116/section/5b6a1a9cf265da0f87595521 收获: 转载 1. Nett ...

  3. Android基于socket的群聊程序

    在网上看了好多,但是感觉不是太简单就是只能单独聊,所以就自己写了个可以群聊的,直接上代码了 一.服务器端 这里用的MyEclipse作为服务器端 MyServerScoket.java package ...

  4. 一例完整的websocket实现群聊demo

    前言 业余我都会花一些时间在tcp.http和websocket等领域的学习,现在觉得有点收获,所以把一个基于websocket的群聊功能的例子提供给大家玩玩.当然这是一个很完整的例子,包括webso ...

  5. 一套高可用、易伸缩、高并发的IM群聊架构方案设计实践

    本文原题为“一套高可用群聊消息系统实现”,由作者“于雨氏”授权整理和发布,内容有些许改动,作者博客地址:alexstocks.github.io.应作者要求,如需转载,请联系作者获得授权. 一.引言 ...

  6. 基于itchat的微信群聊小助手基础开发(一)

    前段时间由于要管理微信群,基于itchat开发了一个简单的微信机器人 主要功能有: 图灵机器人功能 群聊昵称格式修改提示 消息防撤回功能 斗图功能 要开发一个基于itchat的最基本的聊天机器人,在g ...

  7. 基于Kurento的WebRTC移动视频群聊技术方案

    说在前面的话:视频实时群聊天有三种架构: Mesh架构:终端之间互相连接,没有中心服务器,产生的问题,每个终端都要连接n-1个终端,每个终端的编码和网络压力都很大.群聊人数N不可能太大. Router ...

  8. 基于ejabberd简单实现xmpp群聊离线消息

    首先,xmpp服务器是基于ejabberd.离线消息模块是mod_interact,原地址地址:https://github.com/adamvduke/mod_interact: 修改后实现群聊离线 ...

  9. Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)

    一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(en ...

随机推荐

  1. Zabbix常用监控项整理

    zabbix常用key:http://blog.51cto.com/ttxsgoto/1771752 linux主机cpu使用率超过90%的时候报警:https://blog.csdn.net/reb ...

  2. 场景实践篇二:Nginx作为缓存

    cd /etc/nginx/conf.d/ vim cache_test.conf

  3. addEventListener和onclick的区别

    onclick只出现一次alert:我是click2[很正常第一次click事件会被第二次所覆盖],但是addEventListener却可以先后运行,不会被覆盖[正如:它允许给一个事件注册多个监听器 ...

  4. Create Access Point on Archlinux

    Create Access Point on Archlinux */--> Create Access Point on Archlinux 1 Solution Download creat ...

  5. [LC] 22. Generate Parentheses

    Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...

  6. leaflet本地加载arcgis切片

    var origin = [-20037700, 33711400];//图层起点坐标 var resolutions = [ 8466.6836000338681, // Level 0 4233. ...

  7. leaflet加载各种地图

    Leaflet调用各种地图的功能十分复杂,幸好有leaflet.ChineseTmsProviders这个插件,这四种地图直接就可以加载进来,十分方便. 下面是我做的例子: <!DOCTYPE ...

  8. 【转】mac os x配置adb命令的方法,苹果电脑设置adb命令的方法

    http://www.myexception.cn/operating-system/1636963.html 步骤如下: 1. 启动终端Terminal (如果当前用户文件夹下已有.bash_pro ...

  9. 有空要解决的错误log

    E/FaceSDK (): FACESDKTimer face score =0.999912 I/FaceTracker(): face_verification used: I/DEBUG ( ) ...

  10. 未释放资源的教训,开发MongoDB连接一定要关闭连接

    废不少工夫将数据存储,全部迁移至mongodb,未作大量改动则是主因. 但遇到奇怪的现象. 程序跑起不久后,mongodb即假死,另起客户端想登陆mongodb都不成. 要重启mongodb服务器才好 ...