这节讲解基于 Netty 快速实现一个聊天小程序。

一、服务端

1. SimpleChatServerHandler(处理器类)

  该类主要实现了接收来自客户端的消息并转发给其他客户端。

 /**
* 服务端处理器
*/
public class SimpleChatServerHandler extends SimpleChannelInboundHandler<String> {
public static ChannelGroup channels
= new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); /**
* 收到新的客户端连接时调用
* 将客户端channel存入列表,并广播消息
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
// 广播加入消息
channels.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入\n");
channels.add(incoming); // 存入列表
} /**
* 客户端连接断开时调用
* 广播消息
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
// 广播离开消息
channels.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 离开\n");
// channel会自动从ChannelGroup中删除
} /**
* 收到消息时调用
* 将消息转发给其他客户端
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel incoming = ctx.channel();
for(Channel channel : channels) { // 遍历所有连接的客户端
if(channel != incoming) { // 其他客户端
channel.writeAndFlush("[" + incoming.remoteAddress() + "] " + msg + "\n" );
} else { // 自己
channel.writeAndFlush("[you] " + msg + "\n" );
}
}
} /**
* 监听到客户端活动时调用
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient: " + incoming.remoteAddress() + " 在线");
} /**
* 监听到客户端不活动时调用
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient: " + incoming.remoteAddress() + " 掉线");
} /**
* 当Netty由于IO错误或者处理器在处理事件抛出异常时调用
* 关闭连接
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient: " + incoming.remoteAddress() + " 异常");
}
}

2. SimpleChatServerInitializer(配置 Channel 类)

  该类添加分隔符协议处理类,解码、编码器还有自定义处理器。

 /**
* 服务器配置初始化
* 添加多个处理器
*/
public class SimpleChatServerInitializer extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加处理类
// 使用'\r''\n'分割帧
pipeline.addLast("framer",
new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
// 解码、编码器
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// 处理器
pipeline.addLast("handler", new SimpleChatServerHandler()); System.out.println("SimpleChatClient: " + ch.remoteAddress() + "连接上");
} }

3. SimpleChatServer(服务端主程序)

  启动服务端。

 /**
* 服务端 main 启动
*/
public class SimpleChatServer {
private int port; // 端口 public SimpleChatServer(int port) {
this.port = port;
} // 配置并开启服务器
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(); // 用来接收进来的连接
EventLoopGroup workerGroup = new NioEventLoopGroup(); // 用来处理已接收的连接 try {
ServerBootstrap sb = new ServerBootstrap(); // 启动NIO服务的辅助启动类
sb.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // 设置如何接受连接
.childHandler(new SimpleChatServerInitializer()) // 配置Channel
.option(ChannelOption.SO_BACKLOG, 128) // 设置缓冲区
.childOption(ChannelOption.SO_KEEPALIVE, true); // 启用心跳机制 System.out.println("SimpleChatServer 启动了");
ChannelFuture future = sb.bind(port).sync(); // 绑定端口,开始接收连接
future.channel().closeFuture().sync(); // 等待关闭服务器(不会发生)
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
System.out.println("SimpleChatServer 关闭了");
}
} public static void main(String[] args) throws Exception {
int port = 8080;
new SimpleChatServer(port).run(); // 开启服务器
}
}

二、客户端

1. SimpleChatClientHandler(处理器类)

  直接输出收到的消息。

 /**
* 客户端处理类
* 直接输出收到的消息
*/
public class SimpleChatClientHandler extends SimpleChannelInboundHandler<String> { @Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg); // 直接输出消息
} }

2. SimpleChatClientInitializer(配置 Channel 类)

  与服务端类似。

 /**
* 客户端配置初始化
* 与服务端类似
*/
public class SimpleChatClientInitializer extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加处理类
// 使用'\r''\n'分割帧
pipeline.addLast("framer",
new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
// 解码、编码器
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// 处理器
pipeline.addLast("handler", new SimpleChatClientHandler());
} }

3. SimpleChatClient(客户端主程序)

  接收来自控制台的消息,每帧以 "\r\n" 结尾,再发给服务端。

 /**
* 客户端
* 开启客户端,接收控制台输入并发送给服务端
*/
public class SimpleChatClient {
private final String host; // IP
private final int port; // 端口 public SimpleChatClient(String host, int port) {
this.host = host;
this.port = port;
} // 配置并运行客户端
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap(); // 客户端辅助启动类
b.group(group) // 客户端只需要一个用来接收并处理连接
.channel(NioSocketChannel.class) // 设置如何接受连接
.handler(new SimpleChatClientInitializer());// 配置 channel
// 连接服务器
Channel channel = b.connect(host, port).sync().channel();
// 读取控制台输入字符
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while(true) {
// 每行成一帧输出,以"\r\n"结尾
channel.writeAndFlush(in.readLine() + "\r\n");
}
} catch (Exception e) {
e.printStackTrace(); // 输出异常
} finally {
group.shutdownGracefully(); // 关闭
}
} public static void main(String[] args) throws Exception {
new SimpleChatClient("localhost", 8080).run(); // 启动客户端
} }

三、运行效果

  先运行服务端程序,然后在运行两次客户端程序,如下:

  服务端输出:

  

  首先连接的客户端输出:

  

  随便选个客户端在控制台输出信息并回车,如下:

   自身输出:

  

  另一客户端输出:

  

  以上……

Netty 聊天小程序的更多相关文章

  1. netty使用以及聊天小程序

    <从零开始搭建游戏服务器>Netty导入创建Socket服务器 Netty入门教程 Netty 聊天小程序

  2. Netty学习——基于netty实现简单的客户端聊天小程序

    Netty学习——基于netty实现简单的客户端聊天小程序 效果图,聊天程序展示 (TCP编程实现) 后端代码: package com.dawa.netty.chatexample; import ...

  3. [Socket]Socket聊天小程序

    一个简单是Socket聊天小程序,读写操作在不同的线程中.服务器端采用线程池. 1.Server import java.io.IOException; import java.net.ServerS ...

  4. 类似微信聊天小程序-网易云信,IM DEMO小程序版本

    类似微信聊天小程序-网易云信,IM DEMO小程序版本 代码地址: https://github.com/netease-im/NIM_Web_Weapp_Demo 云信IM DEMO 小程序版本 ( ...

  5. 基于JAVA网络编程的聊天小程序

    package com.neusoft.edu.socket; import java.io.BufferedReader; import java.io.IOException; import ja ...

  6. QT UDP聊天小程序

    利用QT的UDP技术,实现两个QT程序之间的聊天程序. #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include < ...

  7. java 网络编程(四)----UDP进阶篇聊天小程序

    设计要求:单线程模式,客户端只发送数据,数据的来源为键盘录入,服务器端只接收数据,当客户端发送886的时候,客户端和服务器端都退出. 1. 发送端: public class Send impleme ...

  8. 用Socket编写的聊天小程序

    Socket是什么? 是套接字,除此之外我也不太清楚,先略过 直接上实例,首先服务端: ; //自定义端口号 private string ServerUser = "Tracy" ...

  9. python实现简单的聊天小程序

    概要 这是一个使用python实现一个简单的聊天室的功能,里面包含群聊,私聊两种聊天方式.实现的方式是使用套接字编程的一个使用TCP协议 c/s结构的聊天室 实现思路 x01 服务端的建立 首先,在服 ...

随机推荐

  1. ImageButton设置src图片大小

    需求&起因 有时候没有找到合适大小的资源,需要修改图片大小而且不改变ImageButton的大小.可以通过缩放图片大小的方式改变外观. ImageView的属性android:scaleTyp ...

  2. 通用的Sql存储过程

    CREATE PROCEDURE [dbo].[P_ProcPager] ( @recordTotal INT OUTPUT, --输出记录总数 ), --表名 ) = '*', --查询字段 ) = ...

  3. net 反射30分钟速成

    概述 什么是反射 Reflection,中文翻译为反射.        这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:‘程序集(Assembly)’.‘模块(Module)’. ...

  4. JavaSE Set集合

    明确Set集合接口的特点. java.util.Set接口和java.util.List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collec ...

  5. 了解java虚拟机—JVM相关参数设置(2)

    1.   JVM相关参数设置 JVM相关配置 -XX:+PrintGC 两次次YoungGC,两次FullGC. -XX:+PrintGCDetails 打印GC时的内存,并且在程序结束时打印堆内存使 ...

  6. mongdb基本操作和更新操作

    1.创建数据库 use hqj 不会真正的创建db,只有insert之后才会创建2.查看数据库show dbs3.插入文档db.hqj.insert({name:'111'})4.查看所有的文档sho ...

  7. CentOS 7环境下Pycharm安装流程记录

    1.准备安装文件: 方法1: 使用内置火狐浏览器访问下载最新格式为tar.gz的压缩包 网址:https://www.jetbrains.com/pycharm/download/previous.h ...

  8. python的变量以及常量介绍

    变量概念: 把程序运行过程中产生的中间值保存在内存. 方便后面使用. 命名规范: 1. 数字, 字母, 下划线组成 2. 不能数字开头, 更不能是纯数字 3. 不能用关键字 4. 不要用中文 5. 要 ...

  9. 图片圆角显示与手机版文章页面CSS布局

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 关于在JSP页面用c标签写if语句

    2017年5月28日,晴,心情还不错. 昨晚和同事撸串,回来后继续威士忌走起,喝到凌晨2点多,聊的甚欢.彼此分享了很多自己成长过程中的故事,相互之间有了进一步的了解,友情又进了一步.在以后的时光里,愿 ...