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. git log 附加命令归纳

    git查看历史记录的时候查看每次提交的内容差异: git log -p git限制显示的条数 : git log -p -2 [-2] git简单显示每次提交做了哪些改动: git log --sta ...

  2. [开源] gnet: 一个轻量级且高性能的 Golang 网络库

    Github 主页 https://github.com/panjf2000/gnet 欢迎大家围观~~,目前还在持续更新,感兴趣的话可以 star 一下暗中观察哦. 简介 gnet 是一个基于 Ev ...

  3. 获取Ubuntu的Docker CE

    Docker文档 Docker提供了一种在容器中运行安全隔离的应用程序的方法,它与所有依赖项和库打包在一起. 获取Ubuntu的Docker CE 一.OS要求 需要以下Ubuntu版本的x86_64 ...

  4. java多线程与线程并发一:线程基础回顾

    本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程 线程简单来讲就是程序正在做的事情.多线程即一个程序同时做多件事情,一个线程就是一件事情. 在java中创建线程的方法有两种. 方法一是 ...

  5. sparkSQL 简介

    一.Spark SQL的特点 1.支持多种数据源:Hive.RDD.Parquet.JSON.JDBC等.2.多种性能优化技术:in-memory columnar storage.byte-code ...

  6. jenkins手把手教你从入门到放弃03-安装Jenkins时web界面出现该jenkins实例似乎已离线

    简介 很久没有安装jenkins了,因为之前用的的服务器一直正常使用,令人郁闷的是,之前用jenkins一直没出过这个问题. 令人更郁闷的是,我尝试了好多个历史版本和最新版本,甚至从之前的服务器把je ...

  7. Jquery 处理返回的 Json 数组

    Jquery 处理返回的 Json 数组 <script> for (var i = 0; i < photos.length; ++ i) { console.log(photos ...

  8. Mybatis动态SQL(where元素、set元素、if元素)

    Mybatis动态SQL(where元素.set元素.if元素) - where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句.而且,若语句的开头为“AND”或 ...

  9. Ocelot学习笔记

    最近因工作需要,开始学习Ocelot.首先简单介绍一下,Ocelot是一个基于.net core的开源webapi 服务网关项目,目前已经支持了IdentityServer认证.根据 作者介绍,Oce ...

  10. Bootstrap——面包屑导航(Breadcrumbs)

    面包屑导航(Breadcrumbs)是一种基于网站层次信息的显示方式. Bootstrap 中的面包屑导航(Breadcrumbs)是一个简单的带有 .breadcrumb 类的无序列表. <o ...