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. 暑期集训20190727 水(water)

    [题目描述] 有一块矩形土地被划分成n×m个正方形小块.这些小块高低不平,每一小 块都有自己的高度.水流可以由任意一块地流向周围四个方向的四块地中,但 是不能直接流入对角相连的小块中. 一场大雨后,由 ...

  2. 阿里巴巴开源项目: 基于mysql数据库binlog的增量订阅&消费

    背景 早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求.不过早期的数据库同步业务,主要是基于trigger的方式获取增量变更,不过从2010年开始,阿里系公司开始逐步的尝 ...

  3. 如何让elemengUI中的表格组件相同内容的单元格自动合并

    1. 前言 这两天在工作中遇到这样一个需求:将某个Excel中的数据在页面上以表格形式展示出来,并且尽量保持数据层级与Excel中一致.在原始Excel文件中,对每一行相同的数据都进行了合并,使得数据 ...

  4. 使用Typescript重构axios(十八)——请求取消功能:总体思路

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  5. vue自定义长按指令

    1.前言 在word中,当我们需要删除一大段文本的时候,我们按一下键盘上的退格键,就会删除一个字,当我们长按住退格键时,就会连续不停的删除,这就是键盘按键的长按功能.那么我们也想在网页中让一个按钮也具 ...

  6. 康托展开&逆康托展开学习笔记

    啊...好久没写了...可能是最后一篇学习笔记了吧 题目大意:给定序列求其在全排列中的排名&&给定排名求排列. 这就是康托展开&&逆康托展开要干的事了.下面依次介绍 一 ...

  7. php 全文搜索搜索-讯搜使用

    相信很多朋友遇到过,需要全文搜索的场景,百度了一圈发现了一个xunsearch 首先本地采集了1万篇文章,发现效率还可以. 使用上也很简单,直接上代码 //接收关键词 $xs = new XS('xp ...

  8. 『题解』LibreOJ6277 数列分块入门 1

    更好的阅读体验 Portal Portal1: LibreOJ Description 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间加法,单点查值. Input 第一行输入一个数字 ...

  9. Mybatis中多表关联时,怎么利用association优雅写resultMap来映射vo

    前言 有好一阵没碰mybatis了,这次的项目基于性能考虑,选了mybatis,写着写着,发现有下面的需求,比如两表联查,取其中各一部分字段,怎么更方便地用vo来接,这里犯了难: 我想的是,因为这个s ...

  10. OpenCV的Mat构造函数

    1.函数说明 构造函数:public Mat(int rows, int cols, MatType type, IntPtr data, long step = 0) 可以通过数据指针构造Mat对象 ...