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实现简单的客户端聊天小程序的更多相关文章

  1. Netty 聊天小程序

    这节讲解基于 Netty 快速实现一个聊天小程序. 一.服务端 1. SimpleChatServerHandler(处理器类) 该类主要实现了接收来自客户端的消息并转发给其他客户端. /** * 服 ...

  2. VSTO学习笔记(七)基于WPF的Excel分析、转换小程序

    原文:VSTO学习笔记(七)基于WPF的Excel分析.转换小程序 近期因为工作的需要,要批量处理Excel文件,于是写了一个小程序,来提升工作效率. 小程序的功能是对Excel进行一些分析.验证,然 ...

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

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

  4. Visual Studio 2017中使用正则修改部分内容 如何使用ILAsm与ILDasm修改.Net exe(dll)文件 C#学习-图解教程(1):格式化数字字符串 小程序开发之图片转Base64(C#、.Net) jquery遍历table为每一个单元格取值及赋值 。net加密解密相关方法 .net关于坐标之间一些简单操作

    Visual Studio 2017中使用正则修改部分内容   最近在项目中想实现一个小工具,需要根据类的属性<summary>的内容加上相应的[Description]特性,需要实现的效 ...

  5. 基于gin框架和jwt-go中间件实现小程序用户登陆和token验证

    本文核心内容是利用jwt-go中间件来开发golang webapi用户登陆模块的token下发和验证,小程序登陆功能只是一个切入点,这套逻辑同样适用于其他客户端的登陆处理. 小程序登陆逻辑 小程序的 ...

  6. Winfrom 简单的进度条小程序

    使用Winform空间编写简单的进度条小程序: 所需控件:Lable 标签  TextBox  文本框  progressBar  进度条控件  timer 定时器 下面是源码及效果图: /// &l ...

  7. Netty学习(九)-Netty编解码技术之Marshalling

    前面我们讲过protobuf的使用,主流的编解码框架其实还有很多种: ①JBoss的Marshalling包 ②google的Protobuf ③基于Protobuf的Kyro ④Apache的Thr ...

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

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

  9. 封装简单的API——微信小程序

    前几天自己琢磨微信小程序的基本开发,里边用到的技术包括WebAPI,也就是方法的封装. 当然也可以用ASP.NET MVC WCF来写接口.更简单应该就是 WinForm 简单易部署. 这里用的是 2 ...

随机推荐

  1. Django学习day4——视图和URL配置

    创建一个简单的hello world 在day3中我们第一次运行了服务器,里面是一个django的欢迎页面,那是因为我们没有配置URL和视图,django在底层会自动跳转这个页面上 我们在mysite ...

  2. 「考试」weight

    正解是树剖. 首先Kru求最小生成树. 然后分别考虑树边和非树边的答案. 首先是非树边,非树边链接的两个点在MST上能够构成一条链. 这条链上最大的那条边-1就是这条边的答案. 为什么. 模拟Kru的 ...

  3. net core WebApi——April.Util更新之权限

    目录 前言 权限 中间层 小结 前言 在之前已经提到过,公用类库Util已经开源,目的一是为了简化开发的工作量,毕竟有些常规的功能类库重复率还是挺高的,二是为了一起探讨学习软件开发,用的人越多问题也就 ...

  4. 「Usaco2005 Dec」清理牛棚(spfa秒杀线段树dp)

    约翰的奶牛们从小娇生惯养,她们无法容忍牛棚里的任何脏东西. 约翰发现,如果要使这群有洁癖的奶牛满意,他不得不雇佣她们中的一些来清扫牛棚, 约翰的奶牛中有N(1≤N≤10000)头愿意通过清扫牛棚来挣一 ...

  5. Pycharm创建项目时 自动添加头部信息

    1.打开PyCharm,选择File--Settings 2.依次选择Editor---Code Style-- File and Code Templates---Python Script 3.. ...

  6. unittest加载测试用例名称必须以test开头,是否可以定制化

    ​ 前几天,在一个群里,一个人问了,这样一个问题.说他面试遇到一个面试官,问他,为啥unittest的测试用例要用test 开头,能不能定制化.他不知道为啥. 看到这个题目,我回答当然可以了,可以用l ...

  7. 【vue】在VS Code中调试Jest单元测试

    在VS Code中调试Jest单元测试 添加调试任务 打开 vscode launch.json 文件,在 configurations 内加入下面代码 "configurations&qu ...

  8. 雅虎日本如何用 Pulsar 构建日均千亿的消息平台

    雅虎日本是一家雅虎和软银合资的日本互联网公司,是日本最受欢迎的门户网站之一.雅虎日本的互联网服务在日本市场占主导地位. 下图从三个维度显示了雅虎日本的经营规模.第一个是服务数量,雅虎日本提供上百种互联 ...

  9. 微信APP支付【签名失败】

    最近在做微信APP支付 遇到一个问题 请求预下单时,接口返回签名错误 由于之前没有成功的交互,刚开始检查程序的错误,经过多次修改,发现依然是签名错误,可能出现的问题如下: 1.该签名密钥不是AppSe ...

  10. OFFICE 2010 每次打开提示安装的问题

    OFFICE2010 安装后每次打开 文件总是提示配置 解决办法: 前提是office已经激活 注册表找到 HKEY_CURRENT_USER\Software\Microsoft\Office\14 ...