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. OV5640摄像头配置一些值得注意的关键点(三)

    一.字节标志的注意点 由于摄像头的输出是RGB56格式,所以需要将两帧的数据进行拼接,之后送到上位机进行显示. reg byte_flag; always@(posedge cmos_pclk_i) ...

  2. NOIP模拟 5

    考试的时候相当浮躁,而且脑子并不工作 T1看了几眼,觉得没思路,先skip T2一打眼,满足条件的最大值,二分!(然后就死了,根本没想有没有单调性) T3找了半天规律,一开始自己手模的K3都过不了样例 ...

  3. ElasticSearch(四):基本搜索

    ElasticSearch(四):基本搜索 学习课程链接<Elasticsearch核心技术与实战> URI Search 使用HTTP的GET方法,在URL中使用查询参数进行查询. GE ...

  4. Salesforce学习之路-developer篇(五)Aura组件原理及常用属性

    很喜欢曾经看到的一句话:以输出倒逼输入.以输出的形式强制自己学习,确实是高效的学习方式,真的很棒.以下仅为个人学习理解,如有错误,欢迎指出,共同学习. 1. 什么是Lightning Componen ...

  5. Spring Cloud gateway 六 Sentinel nacos存储动态刷新

    微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...

  6. Java基础系列5:深入理解Java异常体系

    该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 前言: Java的基 ...

  7. on duplicate key update 的使用(数据库有就修改,没有就添加数据)

    on duplicate key update 使用:当数据库中有该数据就修改,没有就添加 MySQL语句如下: # id 不存在则添加数据,id存在就更新数据 INSERT INTO t_user( ...

  8. Netty处理器重要概念

    1.Netty的处理器可以分为两类:入站处理器和出战处理器 2.入站处理器顶层是ChannelInboundHandler,出战处理器顶层是ChannelOutboundHandler 3.数据处理时 ...

  9. Vue学习笔记:Vue组件的核心概念(下)

    1.双向绑定和单向数据流: 本质上还是单向数据流 视图<——>数据 v-model:仅仅是一个简写,用更少代码去实现功能. 自定义事件 .sync 修饰符 2.虚拟DOM及KEY属性作用 ...

  10. Salesforce学习之路(十二)Aura组件表达式

    1. 表达式语法 在上篇文章组件属性示例中,新建了一个属性whom, 引用该属性时使用了表达式:{!v.whom},负责该属性的动态输出. 语法:{!expression} 上述示例中,我们的属性名称 ...