Netty学习——基于netty实现简单的客户端聊天小程序
Netty学习——基于netty实现简单的客户端聊天小程序
效果图,聊天程序展示 (TCP编程实现)

后端代码:
package com.dawa.netty.chatexample; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; /**
* @Title: MyChatServer
* @Author: 大娃
* @Date: 2019/11/26 09:44
* @Description: 客户端
*/
public class MyChatServer {
public static void main(String[] args) throws InterruptedException {
//定义两个 循环组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup(); try {
//服务器端 启动类
ServerBootstrap serverBootstrap = new ServerBootstrap();
//启动类装载两个 循环组
serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new MyChatServerInitializer());//初始化器 ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync(); }finally {
//关闭循环组
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
package com.dawa.netty.chatexample; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor; /**
* @Title: MyChatServerHandler
* @Author: 大娃
* @Date: 2019/11/26 09:54
* @Description: 消息的广播
* ABC 三个客户端,分别建立服务器的链接
* A,第一个用户,没必要通知
* B,A,B和服务器的控制台都提示 B已经上线,
* C,ABC和服务器端,都是C上线
*
*
* 自己想的:根据生命周期,当注册的时候,提示已经上线,当注销的时候,提示已经下线。
* 当发送一个消息到服务器端的时候,服务器端广播一下。 判断如果是自己的IP的话,提示自己。不是的话,显示IP
*
* netty都是通过响应的回调方法,来进行实现的
* 1.当连接建立好的时候,就代表有一个客户端和服务端建立起连接了、。 handlerAdded
*/
public class MyChatServerHandler extends SimpleChannelInboundHandler<String> { //用来保存一个个的channel对象的。
private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); //收到任何一个消息之后,的回调函数
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel channel = ctx.channel();
channelGroup.forEach(ch -> {
if (channel != ch) {
ch.writeAndFlush(channel.remoteAddress() + "发送的消息:" + msg + "\n");
} else {
ch.writeAndFlush("【自己】" + "发送的消息:" + msg + "\n" );
}
});
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
} /**
* 1.当连接建立好的时候,就代表有一个客户端和服务端建立起连接了。 handlerAdded
* @param ctx
* @throws Exception
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
//1.建立起连接
Channel channel = ctx.channel();
//2.进行广播。
channelGroup.writeAndFlush("【服务器】:" + channel.remoteAddress() + "加入\n");
//3.添加到组
channelGroup.add(channel); //服务器端是不是需要将所有已经建立起连接的channel 保存起来? channelGroup
} /**
* 2.当离开的时候
* @param ctx
* @throws Exception
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
channelGroup.writeAndFlush("【服务器】:" + channel.remoteAddress() + "离开 \n ");
//无需手工的移除, 会自动将断掉的链接移除 。 现在先不管,以后可以看看
// channelGroup.remove(channel);
} @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress()+" 上线");
} @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress()+" 下线");
}
}
package com.dawa.netty.chatexample; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil; /**
* @Title: MyChatServerInitializer
* @Author: 大娃
* @Date: 2019/11/26 09:46
* @Description:
*/
public class MyChatServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//第一个解码器:自带的。 根据分隔符来进行解析
pipeline.addLast(new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
//Handler
pipeline.addLast(new MyChatServerHandler());
}
}
客户端代码: (别人的电脑都可以模拟终端,启动这个客户端即可连接服务器)
package com.dawa.netty.chatexample; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel; import java.io.BufferedReader;
import java.io.InputStreamReader; /**
* @Title: MyChatClient
* @Author: 大娃
* @Date: 2019/11/26 14:39
* @Description:
*/
public class MyChatClient {
public static void main(String[] args) throws Exception {
//循环组,一个就够用了。客户端
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try {
//客户端使用的是bootstrap,
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new MyChatClientInitializer()); //注意此处,使用的是connect,不是使用的bind
Channel channel = bootstrap.connect("localhost", 8899).sync().channel(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); for (; ; ) {
channel.writeAndFlush(br.readLine()+ "\r\n");
} } finally {
eventLoopGroup.shutdownGracefully();
} }
}
package com.dawa.netty.chatexample; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil; /**
* @Title: MyChatClientInitializer
* @Author: 大娃
* @Date: 2019/11/26 14:42
* @Description:
*/
public class MyChatClientInitializer extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline(); //添加Handler
ChannelPipeline channelPipeline = ch.pipeline();
channelPipeline.addLast(new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()));
channelPipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
channelPipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
//添加自己的Handler
pipeline.addLast(new MyChatClientHandler());
}
}
package com.dawa.netty.chatexample; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; /**
* @Title: MyChatClientHandler
* @Author: 大娃
* @Date: 2019/11/26 14:45
* @Description:
*/
public class MyChatClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg);
}
}
Netty学习——基于netty实现简单的客户端聊天小程序的更多相关文章
- Netty 聊天小程序
这节讲解基于 Netty 快速实现一个聊天小程序. 一.服务端 1. SimpleChatServerHandler(处理器类) 该类主要实现了接收来自客户端的消息并转发给其他客户端. /** * 服 ...
- VSTO学习笔记(七)基于WPF的Excel分析、转换小程序
原文:VSTO学习笔记(七)基于WPF的Excel分析.转换小程序 近期因为工作的需要,要批量处理Excel文件,于是写了一个小程序,来提升工作效率. 小程序的功能是对Excel进行一些分析.验证,然 ...
- netty使用以及聊天小程序
<从零开始搭建游戏服务器>Netty导入创建Socket服务器 Netty入门教程 Netty 聊天小程序
- Visual Studio 2017中使用正则修改部分内容 如何使用ILAsm与ILDasm修改.Net exe(dll)文件 C#学习-图解教程(1):格式化数字字符串 小程序开发之图片转Base64(C#、.Net) jquery遍历table为每一个单元格取值及赋值 。net加密解密相关方法 .net关于坐标之间一些简单操作
Visual Studio 2017中使用正则修改部分内容 最近在项目中想实现一个小工具,需要根据类的属性<summary>的内容加上相应的[Description]特性,需要实现的效 ...
- 基于gin框架和jwt-go中间件实现小程序用户登陆和token验证
本文核心内容是利用jwt-go中间件来开发golang webapi用户登陆模块的token下发和验证,小程序登陆功能只是一个切入点,这套逻辑同样适用于其他客户端的登陆处理. 小程序登陆逻辑 小程序的 ...
- Winfrom 简单的进度条小程序
使用Winform空间编写简单的进度条小程序: 所需控件:Lable 标签 TextBox 文本框 progressBar 进度条控件 timer 定时器 下面是源码及效果图: /// &l ...
- Netty学习(九)-Netty编解码技术之Marshalling
前面我们讲过protobuf的使用,主流的编解码框架其实还有很多种: ①JBoss的Marshalling包 ②google的Protobuf ③基于Protobuf的Kyro ④Apache的Thr ...
- 基于JAVA网络编程的聊天小程序
package com.neusoft.edu.socket; import java.io.BufferedReader; import java.io.IOException; import ja ...
- 封装简单的API——微信小程序
前几天自己琢磨微信小程序的基本开发,里边用到的技术包括WebAPI,也就是方法的封装. 当然也可以用ASP.NET MVC WCF来写接口.更简单应该就是 WinForm 简单易部署. 这里用的是 2 ...
随机推荐
- 星级评分条(RatingBar)的功能与用法
星级评分条与拖动条有相同的父类:AbsSeekBar,因此它们十分相似.实际上星际评分条与拖动条的用法.功能都十分接近:它们都允许用户通过拖动来改变进度.RatingBar与SeekBar的最大区别在 ...
- Unity4-用户输入
Input是一个类,可以接收用户的输入 使用AddComponentMenu("Demo1/InputTest1"),将脚本加入到工程中. //例子: void Update() ...
- [2018-07-19] 安装python
1.Python官网 https://www.python.org/downloads/ 2.应该使用Python2.x还是Python3.x? Python有2.x和3.x两个版本,这两个版本是不兼 ...
- Pandas 计算工具介绍
# 导入相关库 import numpy as np import pandas as pd 统计函数 最常见的计算工具莫过于一些统计函数了.首先构建一个包含了用户年龄与收入的 DataFrame i ...
- Zabbix 四 主动模式
本次的主机192.168.131.8 被动模式. 将zabbix4.4.4的源码包放过去,解压安装依赖准备编译安装,并创建zabbix账户. tar -xf zabbix-4.4.0.tar.gz & ...
- CSPS模拟 52
我貌似曾经说过我是个只会做水题的巨型辣鸡.. 这次证明我水题都不会做.. T1 平均数 区间数$n^2$ 枚举是不可能了 可是好像没有无用的计算量.. 刚想到这里,此时开考15min 看见天皇比手势说 ...
- 002.Kubernetes简单入门实例
一 环境准备 1.1 基础环境 Kubernetes模式:单机版 系统环境:CentOS 7/172.24.9.157 部署方式:yum快速部署 其他设置:开启NTP.关闭防火墙及SELinux 二 ...
- php imagick 文字居中的方法
php imagick 文字居中的方法<pre> public function getwenzinfo($nickName) { $nickNamelen = mb_strlen($ni ...
- 利用SSH隧道技术穿越内网访问远程设备
本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/11899478.html 通常,我们用于调试的计算机无法远程访问位于局域网中的待调试设备. ...
- Python 面向对象-下篇
面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中) 对象,根据模板创建的实例(即:对象),实 ...