03_netty实现聊天室功能
【概述】
聊天室主要由两块组成:聊天服务器端(ChatRoomServer)和聊天客户端(ChatClient)。
[ 聊天服务器(ChatRoomServer)功能概述 ]
1.监听所有客户端的接入、断线
2.有客户端A接入聊天室时,将接入消息发给除了客户端A的其他客户端
3.当客户端A退出聊天室时,将退出消息发给除了客户端A的其他客户端
4.当客户端A发送消息到聊天室时,将消息转发给除了客户端A的其他客户端
[ 聊天客户端(ChatClient)功能概述 ]
1.发送消息至聊天服务器
2.接收聊天服务器发送过来的所有消息
【聊天服务端 ChatRoomServer】
/**
* 聊天室服务端
*/
public class ChatRoomServer { private final int port ; public ChatRoomServer(int port) {
this.port = port;
} public void start(){
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try{
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss,worker)
.channel(NioServerSocketChannel.class)
.childHandler(new ChatServerInitialize())
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = bootstrap.bind(port).sync();
future.channel().closeFuture().sync(); }catch (Exception e){
e.printStackTrace();
}finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
} public static void main(String[] args) {
new ChatRoomServer(9999).start(); //服务端监听本地的9999端口
}
}
【ChatServerInitialize】
public class ChatServerInitialize extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel channel) throws Exception {
System.out.println("用户【"+channel.remoteAddress()+"】接入聊天室......");
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast("framer",new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder",new StringDecoder());
pipeline.addLast("encoder",new StringEncoder());
pipeline.addLast("handler",new ChatServerHandler());
}
}
【ChatServerHandler】
/**
* 聊天服务器对各种情况的处理
*/
public class ChatServerHandler extends SimpleChannelInboundHandler<String> { public static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); /**
* 当从服务端收到新的客户端连接时
* 客户端的 Channel 存入 channels 列表中,并通知列表中的其他客户端 Channel
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel clientChannel = ctx.channel();
channels.add(clientChannel);
for (Channel ch : channels) {
if (ch != clientChannel) { //通知除了自己以外的其他用户
ch.writeAndFlush("【提示】:用户【" + clientChannel.remoteAddress() + "】进入聊天室...\n");
}
}
} /**
* 每当从服务端收到客户端断开时
* 客户端的 Channel 自动从 channels 列表中移除了,并通知列表中的其他客户端 Channel
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel clientChannel = ctx.channel();
channels.remove(clientChannel);
for (Channel ch : channels) {
if (ch != clientChannel) { //通知除了自己以外的其他用户
ch.writeAndFlush("【提示】:用户【" + clientChannel.remoteAddress() + "】退出聊天室...\n");
}
}
} /**
* 接受到客户端发出的消息
* 判断channel是否是
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel clientChannel = ctx.channel();
for (Channel ch : channels) {
if (ch != clientChannel) {
ch.writeAndFlush("用户【" + clientChannel.remoteAddress() + "】说:" + msg + "\n");
} else {
ch.writeAndFlush("【我】说:" + msg + "\n");
}
}
} /**
* 服务端监听到客户端活动
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel clientChannel = ctx.channel();
System.out.println("用户【"+clientChannel.remoteAddress()+"】在线中...");
} /**
* 服务端监听到客户端 不活动
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel clientChannel = ctx.channel();
System.out.println("用户【 " +clientChannel.remoteAddress()+"】:离线了"); }
}
【ChatClient 聊天客户端】
/**
* 聊天客户端
*/
public class ChatClient { private final String host; private final int port; public ChatClient(String host, int port) {
this.host = host;
this.port = port;
} public void start() {
EventLoopGroup worker = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap(); try{
bootstrap.group(worker)
.channel(NioSocketChannel.class)
.handler(new ClientInitializer());
Channel channel = bootstrap.connect(host,port).sync().channel();
//客户端从键盘输入数据
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
while(true){
channel.writeAndFlush(input.readLine()+"\n");
}
}catch (Exception e){
e.printStackTrace();
}finally {
worker.shutdownGracefully();
}
} public static void main(String[] args) {
new ChatClient("127.0.0.1",9999).start(); //连接服务器端
} }
【ChatClientInitializer 】
public class ChatClientInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//当有客户端连接服务器时,netty会调用这个初始化器的 initChannel方法
System.out.println("客户端开始初始化......");
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("framer",new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder",new StringDecoder());
pipeline.addLast("encoder",new StringEncoder());
pipeline.addLast("handler",new ChatClientHandler());
}
}
【ChatClientHandler】
public class ChatClientHandler extends SimpleChannelInboundHandler<String> {
/**
* 打印服务端发送过来的数据
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
System.out.println(s);
}
}
【运行结果】
[1.启动聊天服务器]

[2.启动一个客户端A]


[3.再启动一个客户端B]



[4.客户端A发送消息]


[5.客户端A关闭]


03_netty实现聊天室功能的更多相关文章
- Netty学习笔记(四) 简单的聊天室功能之服务端开发
前面三个章节,我们使用了Netty实现了DISCARD丢弃服务和回复以及自定义编码解码,这篇博客,我们要用Netty实现简单的聊天室功能. Ps: 突然想起来大学里面有个课程实训,给予UDP还是TCP ...
- 使用epoll实现聊天室功能,同时比较epoll和select的异同
1.首先介绍一下select和epoll的异同,如下(摘抄自https://www.cnblogs.com/Anker/p/3265058.html) select的几大缺点: (1)每次调用sele ...
- [Python] socket发送UDP广播实现聊天室功能
一.说明 本文主要使用socket.socket发送UDP广播来实现聊天室功能. 重点难点:理解UDP通讯流程.多线程.UDP广播收发等. 测试环境:Win10\Python3.5. 程序基本流程:创 ...
- SignalR实现在线聊天室功能
一.在线聊天室 1.新建解决方案 SignalROnlineChatDemo 2.新建MVC项目 SignalROnlineChatDemo.Web (无身份验证) 3.安装SignalR PM> ...
- PHP 之websocket实现聊天室功能
一.功能界面 具体的详细代码:https://github.com/yangsphp/websocket-master/tree/master 二.具体代码实现 1.前端代码如下 <!DOCTY ...
- 黑科技!仅需 3 行代码,就能将 Gitter 集成到个人网站中,实现一个 IM 即时通讯聊天室功能?
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 高级架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- java web利用mvc结构实现简单聊天室功能
简单聊天室采用各种内部对象不适用数据库实现. 一个聊天室要实现的基本功能是: 1.用户登录进入聊天室, 2.用户发言 3.用户可以看见别人发言 刚才算是简单的需求分析了,现在就应该是进 ...
- 通过WebSocket实现一个简单的聊天室功能
WebSocket WebSocket是一个协议,它是是基于TCP的一种新的网络协议,TCP协议是一种持续性的协议,和HTTP不同的是,它可以在服务器端主动向客户端推送消息.通过这个协议,可以在建立一 ...
- Netty学习笔记(六) 简单的聊天室功能之WebSocket客户端开发实例
在之前的Netty相关学习笔记中,学习了如何去实现聊天室的服务段,这里我们来实现聊天室的客户端,聊天室的客户端使用的是Html5和WebSocket实现,下面我们继续学习. 创建客户端 接着第五个笔记 ...
随机推荐
- [BZOJ 5155][Tjoi2014]电源插排
传送门 网上大部分题解都写得是动态开点线段树,然而像\(MiEcoku\)这么懒惰的显然不会去写线段树... \(\color{green}{solution}\) 我们考虑来点骚操作. 线段树维护的 ...
- 北航操作系统实验2019:Lab4-1流程梳理
北航操作系统实验2019:Lab4-1流程梳理 前言 操作系统的实验课实在令人头秃.我们需要在两周时间内学习相关知识.读懂指导书.读懂代码.补全代码.处理玄学bug和祖传bug,以及回答令人窒息的思考 ...
- OS X获取process.env.NODE_ENV出错
原来项目是其它小组在维护,现在我们需要维护部分功能,把项目带到OS X上运行发现 webpack.config.js获取process.env.NODE_ENV变量出错 解决: 根据电脑操作系统平台类 ...
- wap 往下拉自动加载更多数据
var stop=true; $(window).scroll(function(){ totalheight = parseFloat($(window).height()) + parseFloa ...
- Windows下的SASS环境搭建
虽然眼下 CSS 预编译框架不少,但 SASS 已经逐渐成为主流了,为了更好的适应社会,满足市场需求,获取新技能是必须的. 之前一直想使用 SASS,但都碍于它需要在 ruby 环境下编译而退缩了,这 ...
- java外观模式(Facade)
1.外观模式(Facade [fə'sɑd] n. 正面:表面:外观) 外观模式:可以理解为 中介模式(没错,就是在用户与系统之间,增加了一个类,而这个类就是外观类,所以这个模式就叫外观模式) 如下图 ...
- Weblogic Maven
从weblogic 10.3.4开始支持maven deploy部署 步骤如下: 1.构建weblogic-maven-plugin jar 在D:\oracle\Middleware\wlser ...
- cursor : 普通,带参,可更新的游标。使用游标遍历时,强烈建议用for循环!!!
cursor: 源数据表account中仅有两条记录: 如果输出在判断前,则出错,将最后一条记录输出两次,如下: 所以,一定要先判断notfound再输出结果: exit when (c%notfou ...
- python36异步任务 获取ip地址的地理位置
# encoding: utf-8 import asyncio import requests import functools url = "http://ip.zxinc.org/ap ...
- Delphi下OpenGL2d绘图(03)-画线
一.前言 画线与画点基本上代码是相同.区别在于glBegin()的参数.绘制的框架代码可以使用 Delphi下OpenGL2d绘图(01)-初始化 中的代码.修改的部份为 Draw 函数的内容. 二. ...