Netty 聊天小程序
这节讲解基于 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 聊天小程序的更多相关文章
- netty使用以及聊天小程序
<从零开始搭建游戏服务器>Netty导入创建Socket服务器 Netty入门教程 Netty 聊天小程序
- Netty学习——基于netty实现简单的客户端聊天小程序
Netty学习——基于netty实现简单的客户端聊天小程序 效果图,聊天程序展示 (TCP编程实现) 后端代码: package com.dawa.netty.chatexample; import ...
- [Socket]Socket聊天小程序
一个简单是Socket聊天小程序,读写操作在不同的线程中.服务器端采用线程池. 1.Server import java.io.IOException; import java.net.ServerS ...
- 类似微信聊天小程序-网易云信,IM DEMO小程序版本
类似微信聊天小程序-网易云信,IM DEMO小程序版本 代码地址: https://github.com/netease-im/NIM_Web_Weapp_Demo 云信IM DEMO 小程序版本 ( ...
- 基于JAVA网络编程的聊天小程序
package com.neusoft.edu.socket; import java.io.BufferedReader; import java.io.IOException; import ja ...
- QT UDP聊天小程序
利用QT的UDP技术,实现两个QT程序之间的聊天程序. #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include < ...
- java 网络编程(四)----UDP进阶篇聊天小程序
设计要求:单线程模式,客户端只发送数据,数据的来源为键盘录入,服务器端只接收数据,当客户端发送886的时候,客户端和服务器端都退出. 1. 发送端: public class Send impleme ...
- 用Socket编写的聊天小程序
Socket是什么? 是套接字,除此之外我也不太清楚,先略过 直接上实例,首先服务端: ; //自定义端口号 private string ServerUser = "Tracy" ...
- python实现简单的聊天小程序
概要 这是一个使用python实现一个简单的聊天室的功能,里面包含群聊,私聊两种聊天方式.实现的方式是使用套接字编程的一个使用TCP协议 c/s结构的聊天室 实现思路 x01 服务端的建立 首先,在服 ...
随机推荐
- 第20课-数据库开发及ado.net 可空值类型,资料管理器,多条件查询,Case
第20课-数据库开发及ado.net 可空值类型,资料管理器,多条件查询,Case SqlHelper using System; using System.Collections.Generic; ...
- Factorial Problem in Base K(zoj3621)
Factorial Problem in Base K Time Limit: 2 Seconds Memory Limit: 65536 KB How many zeros are there in ...
- Fibonacci (hdu1568)数学公式
Fibonacci Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- SpringBoot -- 事件(Application Event)
Spring的事件为Bean与Bean之间的消息通信提供了支持,当一个Bean处理完一个任务之后,希望另外一个Bean知道并能做相应的处理,这时我们就需要让一个Bean监听当前Bean所发送的事件. ...
- vue-resource获取不了数据,和ajax的区别,及vue-resource用法
前几天用vue-resource调用接口,用post方式给后端,发现后端php接受不到数据,这好奇怪,最后发现提交给后端的时候 需要加一个参数 就是:emulateJSON : true 这句话的意思 ...
- django-csrf攻击
一.原理 csrf(Cross Site Request Forgery, 跨站域请求伪造:CSRF 攻击允许恶意用户在另一个用户不知情或者未同意的情况下,以他的身份执 行操作. CSRF 攻击是黑客 ...
- 关于animation的一些简单基础和使用方法记载
第一次写博客,只是单纯的想把我自己的一些心得和使用过的css3的animation的一些方法记录和总结,方便下次使用,我写的这些都是刚入门适合做一些简单的动画动作,过于复杂的还有待发掘或者使用别的方法 ...
- 语义SLAM的数据关联和语义定位(一)
语义SLAM和多传感器融合是自动驾驶建图和定位部分比较热门的两种技术.语义SLAM中,语义信息的数据关联相较于特征点的数据关联有所不同.我们一般用特征描述子的相似性来匹配和关联不同图像中的特征点.特征 ...
- Ubuntu 安装hive + mysql
先安装mysql sudo apt-get update sudo apt-get install mysql-server sudo mysql_secure_installation具体详情请另查 ...
- Cookie、Session 和 Token区别
1 Cookie.Session 和 Token 都是用来做持久化处理的,目的就是让客户端和服务端相互认识.Http 请求默认是不持久的没有状态的,谁也不认识谁. 2 Cookie: 是存放在客户 ...