【概述】

聊天室主要由两块组成:聊天服务器端(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关闭]

最新文章

  1. 安装centos6.5如何选择安装包
  2. jQuery简洁大方的登录页面模板
  3. KnockoutJS 3.X API 第五章 高级应用(5) 使用预处理扩展Knockout绑定语法
  4. elk系列1之入门安装与基本操作
  5. javascript基础笔记学习
  6. floor()函数 向下取整 ceil()函数向上取整
  7. Android开发之AChartEngine的使用
  8. Round #3
  9. 一个.net的程序员如何转到java的?
  10. 含有Date属性的对象转化为Json
  11. quepy
  12. less的安装与用法
  13. @Resource 注解的使用
  14. tail -f 实时查看日志文件 linux查看日志后100行
  15. 控制 datetimepicker 显示位置
  16. Linux内核分析第十八章读书笔记
  17. linux c编程操作数据库(sqlite3应用)
  18. RAC禁用DRM特性
  19. Haskell语言学习笔记(31)ListT
  20. [模式识别].(希腊)西奥多里蒂斯&amp;lt;第四版&amp;gt;笔记5之__特征选取

热门文章

  1. shiro原理及其运行流程介绍
  2. 基于聚类的“图像分割”(python)
  3. Mac下安装Iterm2终端工具
  4. 开源前夕先给大家欣赏一下我用C语言开发的云贴吧 网站自动兼容-移动、手机、PC自动兼容云贴吧
  5. Android版本信息及与Linux和Java的关系
  6. HUE配置文件hue.ini 的liboozie和oozie模块详解(图文详解)(分HA集群)
  7. python中的生成器(一)
  8. 使用 JFlex
  9. Caffe入门随笔
  10. 举一反三 willDisplayCell在UICollectionView中的一些应用