Netty学习——实战篇4 Netty开发Http服务实战、ByteBuf使用、开发群聊系统

1 Netty开发Http服务实战

        (1)Netty服务器监听8000端口,浏览器发出请求“http://localhost:8000”

        (2)服务器可以回复消息给客户端,“你好,我是服务器”,并对特定请求资源进行过滤。

HttpServer.java
public class HttpServer {public static void main(String[] args) throws Exception{//1 创建bossGroup和workerGroup线程组NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);NioEventLoopGroup workerGroup = new NioEventLoopGroup();try {//创建ServerBootstrap对象ServerBootstrap serverBootstrap = new ServerBootstrap();//配置ServerBootstrap对象serverBootstrap.group(bossGroup,workerGroup) // 设置两个线程组.channel(NioServerSocketChannel.class) //使用NIOServerSocketChannel作为服务端的通道.childHandler(new ServerInitializer()); //设置Handler//绑定端口并异步启动ChannelFuture channelFuture = serverBootstrap.bind(8000).sync();// 监听 关闭通道事件channelFuture.channel().closeFuture().sync();}finally {//关闭线程组bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
HttpServerHandler.java
/*SimpleChannelInboundHandler 是 ChannelInboundHandlerAdapter的子类HttpObject 封装了客户端和服务端相互通讯的数据*/
@Slf4j
public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {//读取客户端数据@Overrideprotected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {log.info("对应的channel是:{},pipeline是:{},通过pipeline获取channel是:{}",ctx.channel(),ctx.pipeline(),ctx.pipeline().channel());log.info("当前ctx的handler是:{}",ctx.handler());//获取//判断 msg 是不是HttpRequest请求if(msg instanceof HttpRequest){log.info("ctx类型是:{}",ctx.getClass());log.info("pipeline的hashcode是:{},HttpServerHandler的 hashcode是:",ctx.pipeline().hashCode(),this.hashCode());log.info("msg类型是:{}",msg.getClass());log.info("客户端地址是:{}",ctx.channel().remoteAddress());//获取httpRequestHttpRequest request = (HttpRequest) msg;//获取uriString uri = request.uri();//过滤指定的资源if("/favicon.ico".equals(uri)){log.info("请求了 favicon.ico, 不做响应");return;}//回复信息到浏览器(http协议)ByteBuf content = Unpooled.copiedBuffer("hello,我是服务器",CharsetUtil.UTF_8);//构造一个http的响应FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,content);response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());//把构建好的response返回ctx.writeAndFlush(response);}}
}
ServerInitializer.java
@Slf4j
public class ServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {//向管道加入处理器//获取管道ChannelPipeline pipeline = ch.pipeline();//加入一个netty 提供的httpServerCodec codec =>[coder - decoder]//HttpServerCodec 说明//1. HttpServerCodec 是netty 提供的处理http的 编-解码器pipeline.addLast("MyHttpServerCodec",new HttpServerCodec());//2  加入自定义的handlerpipeline.addLast("MyHandler",new HttpServerHandler());log.info("服务初始化完成");}
}

2 ByteBuf实战

ByteBuf01.java,使用 Unpooled.buffer()方法创建ByteBuf对象

public class ByteBuf01 {public static void main(String[] args) {ByteBuf buffer = Unpooled.buffer(10);//写入数据for (int i = 0; i < 10; i++) {buffer.writeByte(i);}System.out.println("buffer的容量是= "+ buffer.capacity());System.out.println("buffer的readerIndex = "+ buffer.readerIndex());System.out.println("buffer的writerIndex = "+ buffer.writerIndex());//读取数据for (int i = 0; i < buffer.capacity(); i++) {System.out.print(buffer.readByte() + " ");}System.out.println();System.out.println("buffer的容量是= "+ buffer.capacity());System.out.println("buffer的readerIndex = "+ buffer.readerIndex());System.out.println("buffer的writerIndex = "+ buffer.writerIndex());}
}

运行结果:

NettyByteBuf02.java.使用 Unpooled.copiedBuffer()创建ByteBuf对象

@Slf4j
public class ByteBuf02 {public static void main(String[] args) {ByteBuf byteBuf = Unpooled.copiedBuffer("你好,世界!", Charset.forName("utf-8"));if(byteBuf.hasArray()){//把ByteBuf转换成byte[]byte[] content = byteBuf.array();//把byte[]转换成字符串String result = new String(content, Charset.forName("utf-8"));log.info("result = {}",result);log.info("偏移量 = {}",byteBuf.arrayOffset());log.info("readerIndex = {}",byteBuf.readerIndex());log.info("writerIndex = {}",byteBuf.writerIndex());log.info("capacity = {}",byteBuf.capacity());for (int i = 0; i < byteBuf.readableBytes(); i++) {log.info("内容是:{}",byteBuf.readByte());}log.info("result = {}",result);log.info("偏移量 = {}",byteBuf.arrayOffset());log.info("readerIndex = {}",byteBuf.readerIndex());log.info("writerIndex = {}",byteBuf.writerIndex());log.info("capacity = {}",byteBuf.capacity());}}
}

运行结果

3 群聊系统

3.1 需求

        (1)编写一个Netty群聊系统,实现服务器和客户端之间的数据简单通讯(非阻塞)

        (2)实现多人群聊

        (3)服务端:可以监测用户上线,离线,并实现消息转发功能

        (4)客户端:通过channel可以无阻塞发送消息给其他用户,同时可以接收其他用户发送的消息(通过服务器转发获取)

3.2 服务器代码

NettyChatServer.java

@Slf4j
public class NettyChatServer {//监听端口private int port;public NettyChatServer(int port) {this.port = port;}public void run(){//创建两个线程组 bossGroup和workerGroupNioEventLoopGroup bossGroup = new NioEventLoopGroup(1);NioEventLoopGroup workerGroup = new NioEventLoopGroup();try {//创建ServerBootstrap对象ServerBootstrap serverBootstrap = new ServerBootstrap();//设置serverBootstrapserverBootstrap.group(bossGroup,workerGroup)  //设置bossGroup和workerGroup.channel(NioServerSocketChannel.class) //使用NIOServerSocketChannel作为服务端的通道.option(ChannelOption.SO_BACKLOG,128) // 设置bossGroup 最大连接数量.childOption(ChannelOption.SO_KEEPALIVE,true) //设置workerGroup 保持活动状态.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {//获取pipelineChannelPipeline pipeline = ch.pipeline();//向pipeline加入解码器pipeline.addLast("decoder",new StringDecoder());//向pipeline加入编码器pipeline.addLast("encoder",new StringEncoder());//向pipeline加入自定义handlerpipeline.addLast(new NettyChatServerHandler());}});log.info("服务器启动成功");//绑定端口并启动ChannelFuture channelFuture = serverBootstrap.bind(port).sync();channelFuture.channel().closeFuture().sync();}catch (Exception e){e.printStackTrace();}finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}public static void main(String[] args) {new NettyChatServer(8000).run();}
}

3.3 服务端Handler

NettyChatServerHandler.java

@Slf4j
public class NettyChatServerHandler extends SimpleChannelInboundHandler<String> {//创建通道组,管理所有连接的通道。GlobalEventExecutor.INSTANCE 是一个全局事件执行器,为单例private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);//日期SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//当有新的连接时,执行该方法@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {//获取通道Channel channel = ctx.channel();//通知:客户端上线ctx.writeAndFlush("[客户端]" + channel.remoteAddress() + "在" + sdf.format(new Date()) + "加入聊天");//把通道加入通道组channels.add(channel);}//当连接断开时,执行该方法@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();ctx.writeAndFlush("[客户端]" + channel.remoteAddress() + "在" + sdf.format(new Date()) + "离开了");}//channel处于活动状态,提示:上线了@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();log.info("{} 上线了" ,channel.remoteAddress());}//channel 处于不活动状态,提示离线了@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();log.info("{} 离线了",channel.remoteAddress());}//转发消息@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {Channel ch1 = ctx.channel();System.out.println("ch1 = " + ch1);channels.forEach(ch ->{System.out.println("ch = " +  ch);if(ch1 != ch){ch.writeAndFlush("[用户]" + ch1.remoteAddress() + "在" +sdf.format(new Date()) + "时间发送了消息" + msg + "\n");}});}//发生异常时,关闭通道@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}
}

3.4 客户端代码

NettyChatClient.java

@Slf4j
public class NettyChatClient {private  String host;private  int port;public NettyChatClient(String host, int port) {this.host = host;this.port = port;}private void run(){NioEventLoopGroup loopGroup = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(loopGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("decoder",new StringDecoder());pipeline.addLast("encoder",new StringEncoder());pipeline.addLast(new NettyChatClientHandler());}});ChannelFuture channelFuture = bootstrap.connect(host, port).sync();Channel channel = channelFuture.channel();log.info("客户端连接成功,地址是:{}",channel.remoteAddress());Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()){String msg = scanner.nextLine();channel.writeAndFlush(msg + "\r\n");}}catch (Exception e){e.printStackTrace();}finally {loopGroup.shutdownGracefully();}}public static void main(String[] args) {new NettyChatClient("127.0.0.1",8000).run();}
}

3.5 客户端Handler

NettyChatClientHandler.java

public class NettyChatClientHandler extends SimpleChannelInboundHandler<String> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {System.out.println(msg.trim());}
}

3.6 运行结果

服务端:

客户端001

 

客户端002

客户端003

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/625618.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

连连看游戏页面网站源码,直接使用

可以上传自己喜欢的图片 游戏页面 通关页面 源码免费下载地址抄笔记 (chaobiji.cn)

Docker之自定义镜像上传至阿里云

一、Alpine介绍 Alpine Linux是一个轻量级的Linux发行版&#xff0c;专注于安全、简单和高效。它采用了一个小巧的内核和基于musl libc的C库&#xff0c;使得它具有出色的性能和资源利用率。 Alpine Linux的主要特点包括&#xff1a; 小巧轻量&#xff1a;Alpine Linux的安装…

内网隧道技术总结

隧道技术解决的是网络通信问题&#xff0c;因为在内网环境下&#xff0c;我们不同的内网主机管理员会进行不同的网络配置&#xff0c;我们就需要使用不同的方式去控制我们的内网主机。隧道技术是一个后渗透的过程&#xff0c;是可以是我们已经取得了一定的权限&#xff0c;在这…

二维码门楼牌管理应用平台建设:场所维护的新篇章

文章目录 前言一、二维码门楼牌管理应用平台的兴起二、民警与网格员的角色定位三、场所信息审核的重要性四、技术支持与创新应用五、未来展望与挑战 前言 随着信息技术的飞速发展&#xff0c;二维码门楼牌管理应用平台的建设正成为城市管理的新宠。该平台不仅提高了场所管理的…

如何恢复硬盘数据?小白也要掌握的4个方法!

“我将很多重要的文件都保存在电脑里了&#xff0c;不知道是电脑中病毒还是什么原因&#xff0c;我有些比较重要的数据丢失了&#xff0c;有什么方法可以恢复丢失的电脑数据吗&#xff1f;” 硬盘作为电脑存储数据的核心部件&#xff0c;一旦数据丢失或损坏&#xff0c;往往会给…

新手小白花几个月勇敢裸辞转行网络安全

我是 25 岁转行学网络安全的。说实在&#xff0c;转行就是奔着挣钱去的。希望我的经历可以给想转行的朋友带来一点启发和借鉴。 先简单介绍下个人背景&#xff0c;三流大学毕业&#xff0c;物流专业&#xff0c;学习能力一般&#xff0c;没啥特别技能&#xff0c;反正就很普通…

SCI一区 | Matlab实现POA-TCN-BiGRU-Attention鹈鹕算法优化时间卷积双向门控循环单元注意力机制多变量时间序列预测

SCI一区 | Matlab实现POA-TCN-BiGRU-Attention鹈鹕算法优化时间卷积双向门控循环单元注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现POA-TCN-BiGRU-Attention鹈鹕算法优化时间卷积双向门控循环单元注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考…

C++入门之类和对象

C入门之类和对象 文章目录 C入门之类和对象1. 类的6个默认对象2. 构造函数2.1 概念2.2 特性2.3 补丁 3. 析构函数3.1 概念3.2 特性3.3 总结 4. 拷贝构造函数4.1 概念4.2 特性4.3 总结 1. 类的6个默认对象 如果一个类中什么都没有&#xff0c;那么这个类就是一个空类。但是&…

自动化测试Selenium(3)

目录 WebDriver相关API 打印信息 打印title 打印url 浏览器的操作 浏览器最大化 设置浏览器的宽,高 操作浏览器的前进, 后退, 刷新 控制浏览器滚动条 键盘事件 键盘单键用法 键盘组合按键用法 鼠标事件 WebDriver相关API 打印信息 打印title 即打印该网址的标题.…

2023图灵奖揭晓,你怎么看?

Avi Wigderson&#xff0c;以色列裔美国数学家&#xff0c;普林斯顿高级研究学院教授&#xff0c;以其在理论计算机科学和数学中的杰出贡献而闻名。 他在1956年生于以色列海法&#xff0c;后来在1974年至1980年在以色列理工学院学习&#xff0c;获得数学和计算机科学的学士和硕…

量子城域网系列(五):几种典型的量子密钥分发网络组网结构

在上之前文章中&#xff0c;我们介绍了最基本的点对点量子保密通信网络形式以及组网方案&#xff0c;但是显然在实际的应用中&#xff0c;点对点的通信是比较少的&#xff0c;大多还是需要多个终端进行互联才能构成网络。本文我们就讨论一下几种基础的量子密钥分发网络组网结构…

2023年图灵奖颁发给艾维·维格森(Avi Wigderson),浅谈其计算复杂性理论方面做出的重要贡献

Avi Wigderson是一位以色列计算机科学家&#xff0c;他在计算复杂性理论方面做出了重要的贡献&#xff0c;并对现代计算产生了深远的影响。 Wigderson的主要贡献之一是在证明计算复杂性理论中的基本问题的困难性方面。他证明了许多经典问题的困难性&#xff0c;如图论中的图同构…