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 服务端的建立 首先,在服 ...
随机推荐
- HTML 初识 HTML【 整体结构 文字 图片 表格 超链接】
HTML 超文本标记语言,页面内可以包含图片.链接,甚至音乐.程序等非文字元素. 网页的本质就是超级文本标记语言,万维网是建立在超文本基础之上的.TML 通过标记符号来标记要 ...
- [日常] Go语言圣经--接口约定习题2
练习 7.3: 为在gopl.io/ch4/treesort (§4.4)的*tree类型实现一个String方法去展示tree类型的值序列. package main import( "f ...
- MVC Helper Methods
在.net MVC中经常会见到特别的写法 比如 @Url.Action( ) @Url.Conyent( ) @Html.Displayfor( )等等 这些 写法就是我们这里要讲的 Helper ...
- python正则表达式1
使用正则表达式,需要导入re这个模块 >>> import re >>> pattern=r'abc' >>> str='abcdefghijab ...
- js-ES6学习笔记-module(4)
1.<script>标签打开defer或async属性,脚本就会异步加载.渲染引擎遇到这一行命令,就会开始下载外部脚本,但不会等它下载和执行,而是直接执行后面的命令. defer与asyn ...
- css3 content 特殊字符和符号
基本形状 ▲ 9650 25B2 ► 9658 25BA ► 9658 25BA ▼ 9660 25BC◄ 9668 25C4 ❤ 10084 2764 ✈ 9992 2708 ★ 9733 2605 ...
- 前端开发笔记(3)css基础(中)
上一篇中我们学习了html的标准文档流,下面我们先来看看如何脱离标准流. 脱离标准流 css中一共有三种方法脱离标准流 浮动 绝对定位 固定定位 浮动 我们要搞清楚什么是浮动,先来看一个标准文档流的例 ...
- 新飞电器的BI建设案例
一.河南新飞电器简介 河南新飞电器在制造行业内属于领先地位,其信息化程度较高,面对系统多且杂乱的情况,一个集中展示数据的平台就显得尤为重要.使用BI就是为了在一个相对统一的平台展示需要查看的数据,供决 ...
- [Android] 对自定义图片浏览器经常内存溢出的一些优化
首先关于异步加载图片可以参见 夏安明 的博客:http://blog.csdn.net/xiaanming/article/details/9825113 这篇文章最近有了新的更改,大概看了一下,内容 ...
- Spring Boot (#1 quick start)
Spring Boot (#1 quick start) 官方文档 Spring Boot是为了简化Spring应用的创建.运行.调试.部署等而出现的,使用它可以做到专注于Spring应用的开发,而无 ...