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实现,下面我们继续学习. 创建客户端 接着第五个笔记 ...
随机推荐
- LINQ中的"延迟查询"特性【转】
本文转载自:LINQ中的"延迟查询"特性 详细了解“延迟查询”:C#学习笔记(八)—–LINQ查询之延迟执行 很多标准查询操作符的设计原型都是返回一个IEnumerable< ...
- 利用ReentrantLock简单实现一个阻塞队列
借助juc里的ReentrantLock实现一个阻塞队列结构: package demo.concurrent.lock.queue; import java.util.concurrent.lock ...
- win10 ping不通所有地址
电脑使用的很正常,是公司内网,但是在昨天测试数据库连接的时候,所有的地址都ping不通了.原先是可以ping通的,然后各种查,各种尝试. 清空dns缓存, cmd命令查看dns缓存:ipconfig ...
- jsp页面用struts2标签展示List<Object>类型的数据
今天遇到一个问题,一个List<Object>类型的数据,是直接从sql查出来的数据,要在前端展示,原来的方法不知道为什么不能展示,后来找了好久,找到了一个靠谱的方法,记录一下 <s ...
- Mac下利用SSH进行传输文件(转)
//1.从服务器上下载文件 scp username@servername:/path/filename /var/www/local_dir(本地目录) //例如scp root@192.168.0 ...
- jquery的animate关于background-position属性
jQuery 的 animate 虽然能直接使用 CSS 的方式来进行动画,但有些属性其实是不支持的,例如:background-position. 谷歌支持 background-position- ...
- redis 实现消息发布和订阅
1,打开二个客户端机器 一个用于发布,一个用于接受 2,发布一个channel1 3,用另外一个客户端收听上面的客户端 4,当再次在发布的redis客户端 发布一个消息 其他所有订阅的客户端会自动收 ...
- Install NDK in Eclipse/Android Studio
1. Download NDK https://developer.android.com/tools/sdk/ndk/index.html 2.Install NDK $ tar xvf andro ...
- CentOS和Ubuntu系统下安装 HttpFS (助推Hue部署搭建)
不多说,直接上干货! 我的集群机器情况是 bigdatamaster(192.168.80.10).bigdataslave1(192.168.80.11)和bigdataslave2(192.168 ...
- msyql int(x) 中的x
先看一个mysql表结构 Sql代码 CREATE TABLE `test` ( `TYPEID` int (2) ) ENGINE=MyISAM CHARSET=latin1; Sql代码 ...