【初识Netty使用Netty实现简单的客户端与服务端的通信操作Netty框架中一些重要的类以及方法的解析】

news2025/2/23 23:13:49

一.Netty是什么?

image.png

Netty 由 Trustin Lee(韩国,Line 公司)2004 年开发

本质:网络应用程序框架

实现:异步、事件驱动

特性:高性能、可维护、快速开发

用途:开发服务器和客户端

Netty的性能很高,按照Facebook公司开发小组的测试表明,Netty最高能达到接近百万的吞吐。

二.Netty发展历程

  • 2004年6月Netty2发布(声称Java社区中第一个基于事件驱动的应用网络框架)
  • 2008年10月Netty3发布
  • 2013年7月Netty4 发布
  • 2013年12月发布5.0.0.Alpha1
  • 2015年11月废弃5.0.0

三.Netty在开发领域的应用场景

30000+项目在使用(统计方法:依赖项中声明io.netty:netty-all)

  • 数据库:Cassandra
  • 大数据处理:Spark、Hadoop
  • Message Queue: RocketMQ
  • 检索: Elasticsearch
  • 框架:gRPC、Apache Dubbo
  • 分布式协调器:ZooKeeper
  • 工具类: async-http-client

四.第一个Netty程序

4.1 maven中引入一个比较稳定的4.1.25.Final的版本

<dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.1.28.Final</version>
</dependency>

4.2 服务端代码

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.net.InetSocketAddress;

public class Server{

    private final int port;

    public Server  (int port) {
        this.port = port;
    }

    public static void main(String[] args) throws InterruptedException {
        int port = 9999;
        Server server = new Server(port);
        System.out.println("服务器启动");
        server.start();
        System.out.println("服务器关闭");
    }

    public void start() throws InterruptedException {
        final ServerHandler serverHandler = new ServerHandler();
        /*线程组*/
        EventLoopGroup group = new NioEventLoopGroup(1);
        try {
            /*服务端启动必须*/
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)/*将线程组传入*/
                    .channel(NioServerSocketChannel.class)/*指定使用NIO进行网络传输*/
                    .localAddress(new InetSocketAddress(port))/*指定服务器监听端口*/
                    /*服务端每接收到一个连接请求,就会新启一个socket通信,也就是channel,
                    所以下面这段代码的作用就是为这个子channel增加handle*/
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel ch) throws Exception {
                            /*添加到该子channel的pipeline的尾部*/
                            ch.pipeline().addLast(serverHandler);
                        }
                    });
            ChannelFuture f = b.bind().sync();/*异步绑定到服务器,sync()会阻塞直到完成*/
            f.channel().closeFuture().sync();/*阻塞直到服务器的channel关闭*/

        } finally {
            group.shutdownGracefully().sync();/*优雅关闭线程组*/
        }
    }
}

4.3 服务端业务处理

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

@ChannelHandler.Sharable
/*不加这个注解那么在增加到childHandler时就必须new出来*/
public class ServerHandler extends ChannelInboundHandlerAdapter {

    /*服务端读到数据以后,就会执行*/
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf)msg;
        System.out.println("Server accept:"+in.toString(CharsetUtil.UTF_8));
        ctx.writeAndFlush(Unpooled.copiedBuffer("你好,我是服务端,我已经收到你发送的消息", CharsetUtil.UTF_8));
    }

    /*** 服务端读取完成网络数据后的处理*/
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
                .addListener(ChannelFutureListener.CLOSE);
    }

    /*** 发生异常后的处理*/
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

4.4 客户端实现代码

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.InetSocketAddress;

public class Client {

    private final int port;
    private final String host;

    public Client(int port, String host) {
        this.port = port;
        this.host = host;
    }

    public void start() throws InterruptedException {
        /*线程组*/
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            /*客户端启动必备*/
            Bootstrap b = new Bootstrap();
            b.group(group)/*把线程组传入*/
                    /*指定使用NIO进行网络传输*/
                    .channel(NioSocketChannel.class)
                    .remoteAddress(new InetSocketAddress(host,port))
                    .handler(new ClientHandle());
            /*连接到远程节点,阻塞直到连接完成*/
            ChannelFuture f = b.connect().sync();
            /*阻塞程序,直到Channel发生了关闭*/
            f.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Client(9999,"127.0.0.1").start();
    }
}

4.5 客户端业务逻辑处理

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;

public class ClientHandle extends SimpleChannelInboundHandler<ByteBuf> {

    /*客户端读到数据以后,就会执行*/
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg)
            throws Exception {
        System.out.println("client acccept:"+msg.toString(CharsetUtil.UTF_8));
    }

    /*连接建立以后*/
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer(
                "Hello Netty",CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
    }
}

3.6 运行结果:

3.6.1 服务端运行结果:

在这里插入图片描述

3.6.2 客户端运行结果:

在这里插入图片描述

五.Netty框架中一些重要的类以及方法的解析

5.1 EventLoop、ServerBootstrap、Bootstrap

EventLoop暂时可以看成一个线程、EventLoopGroup自然就可以看成线程组。

EventLoopGroup group = new NioEventLoopGroup(1);

网络编程里,“服务器”和“客户端”实际上表示了不同的网络行为;换句话说,是监听传入的连接还是建立到一个或者多个进程的连接。因此,有两种类型的引导:一种用于客户端(简单地称为Bootstrap),而另一种(ServerBootstrap)用于服务器。无论你的应用程序使用哪种协议或者处理哪种类型的数据,唯一决定它使用哪种引导类的是它是作为一个客户端还是作为一个服务器。

//服务端启动创建的对象
ServerBootstrap b = new ServerBootstrap();
//客户端启动创建的对象
Bootstrap b = new Bootstrap();

ServerBootstrap将绑定到一个端口,因为服务器必须要监听连接,而Bootstrap 则是由想要连接到远程节点的客户端应用程序所使用的。

引导一个客户端只需要一个EventLoopGroup,但是一个ServerBootstrap 则需要两个,因为服务器需要两组不同的Channel。第一组将只包含一个ServerChannel,代表服务器自身的已绑定到某个本地端口的正在监听的套接字。而第二组将包含所有已创建的用来处理传入客户端连接(对于每个服务器已经接受的连接都有一个)的Channel。

image.png

Channel 是Java NIO 的一个基本包装构造。

它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作。

目前,可以把Channel 看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者被关闭,连接或者断开连接。

5.2 事件和ChannelHandler、ChannelPipeline

image.png

Netty 使用不同的事件来通知我们状态的改变或者是操作的状态。这使得我们能够基于已经发生的事件来触发适当的动作。

可能由入站数据或者相关的状态更改而触发的事件包括:

连接已被激活或者连接失活;数据读取;用户事件;错误事件。

出站事件是未来将会触发的某个动作的操作结果,这些动作包括:

打开或者关闭到远程节点的连接;将数据写到或者冲刷到套接字。

image.png

每个事件都可以被分发给ChannelHandler 类中的某个用户实现的方法。

Netty 提供了大量预定义的可以开箱即用的ChannelHandler 实现,包括用于各种协议(如HTTP 和SSL/TLS)的ChannelHandler。

5.3 ChannelFuture

Netty 中所有的I/O 操作都是异步的。

JDK 预置了interface java.util.concurrent.Future,Future 提供了一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。但是其所提供的实现,只允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成。这是非常繁琐的,所以Netty提供了它自己的实现——ChannelFuture,用于在执行异步操作的时候使用。

每个Netty 的出站I/O操作都将返回一个 ChannelFuture 。

好了,【初识Netty&使用Netty实现简单的客户端与服务端的通信操作&Netty框架中一些重要的类以及方法的解析】就先学习到这里,更多内容不断学习更新中。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

字符串匹配算法(BF、KMP)

目录 1、暴力匹配&#xff08;BF&#xff09;算法 2、KMP算法 1、暴力匹配&#xff08;BF&#xff09;算法 BF算法&#xff0c;即暴力(Brute Force)算法&#xff0c;是普通的模式匹配算法&#xff0c;BF算法的思想就是将目标串S的第一个字符与模式串T 的第一个字符进行匹配&a…

【树莓派不吃灰】配置samba,文件夹目录配置在闲置U盘,实现局域网文件共享

目录1. 前言2. 安装 Samba2.1 安装samba 和 samba-common-bin2.2 配置/etc/samba/smb.conf文件2.3 配置登录账号和密码2.4 重启 samba 服务2.5 回到windows&#xff0c;就可以在网络当中发现共享的文件夹3. 在Windows上挂载smb的共享目录3.1 打开windows的smb功能3.2 添加网络映…

Java --- springMVC实现RESTFul案例

一、使用springMVC实现RESTFul小案例 1.1、项目目录图&#xff1a; 1.2、代码实现&#xff1a; pom.xml文件&#xff1a; <packaging>war</packaging><!--添加依赖--><dependencies><!--SpringMVC--><dependency><groupId>org.spr…

黑马C++ 03 提高4 —— STL常用容器_string容器/vector容器/deque容器

文章目录一、string容器1. string基本概念2. string构造函数3. string赋值操作4. string字符串拼接5. string查找和替换6. string字符串比较7. string字符存取8. string字符串的插入和删除9. string子串二、vector容器(尾插尾删)1. vector基本概念2. vector构造函数3. vector赋…

【目标检测】基于yolov3的血细胞检测(无bug教程+附代码+数据集)

多的不说,少的不唠,先看检测效果图: 共检测三类:红细胞RBC、白细胞WBC、血小板Platelets Hello,大家好,我是augustqi。今天给大家带来的保姆级教程是:基于yolov3的血细胞检测(无bug教程+附代码+数据集) 1.项目背景 在上一期的教程中,我们基于yolov3训练了一个红细…

韩顺平linux(1-11小节)

运维工程师 服务器的规划、调试优化、日常监控、故障处理 物联网linux Linux主要指的是内核 ubuntu&#xff08;python偏爱&#xff09;&#xff0c;centos 发行版本 内核进行包装 1.4服务器领域 linux在服务器领域的应用是最强的。 linux免费、稳定、高效等特点在这里得到了很…

2019 Sichuan Province Programming Contest J. Jump on Axis

题目链接&#xff1a;https://codeforces.com/gym/102821/problem/J 题意&#xff1a;给你一个坐标k&#xff0c;每次从0开始走 每次有三个选择&#xff1a;选择1走一步&#xff0c;选择2走两步&#xff0c;选择3走三步 每次选第i个选择的时候&#xff0c;如果他没有被选过&…

MySQL是如何保证数据不丢失的

一.什么是两阶段提交 1.SQL语句&#xff08;update user set name‘李四’ where id3&#xff09;的执行流程是怎样的呢&#xff1f; 1.执行器先找引擎取 ID3这一行。ID 是主键&#xff0c;引擎直接用树搜索找到这一行。 2.如果 ID3 这一行所在的数据页本来就在内存中&#x…

力扣算法入门刷题

1、回文数 判断输入的整数是否是回文 我的一般思路&#xff1a; 将输入的整数转成字符串&#xff0c;再将这个字符串转成字符数组c&#xff0c;对字符数组进行遍历&#xff0c;如果第i个元素与第 c.length - i - 1 元素不相等&#xff0c;也就是通过比较首尾元素是否相同来判断…

自动化早已不是那个自动化了,谈一谈自动化测试现状和自我感受……

前言 从2017年6月开始接触自动化至今&#xff0c;已经有好几年了&#xff0c;从17年接触UI自动化&#xff08;unittestselenium&#xff09;到18年接触接口自动化&#xff08;unittestrequests&#xff09;再到18年自己编写自动化平台&#xff08;后台使用python的flask&#…

风、光、柴油机、蓄电池、电网交互微电网经济调度优化问题研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

爆破校园网的宽带

前提&#xff1a;学校的手机号前7位相同&#xff0c;宽带密码都是手机号后六位。仅供学习。 准备工作&#xff1a;电脑一台&#xff0c;把校园网的宽带水晶头插在电脑上&#xff0c; 步骤&#xff1a; winR输入Rasphone点击新建&#xff0c;宽带&#xff0c;输入宽带名称&am…

Vue复刻华为官网 (一)

1 分析 根据华为网页的布局&#xff0c;我们大体上可以将其划分为7个盒子&#xff0c;如下&#xff0c;由于写一个这样的网页再加上部分动态效果&#xff0c;需要的时间很长&#xff0c;本篇博客只记录了div1、div2、div3的静态效果轮播图的实现。 2 顶部盒子的实现 想要实现的…

【C++AVL树】4种旋转详讲

目录 引子&#xff1a;AVL树是因为什么出现的&#xff1f; 1.AVl树的的特性 2.AVl树的框架 3.AVL树的插入 3.1四种旋转&#xff08;左单旋、右单旋、左右双旋、右左双旋&#xff09; 3.1.1左单旋 3.1.2右单旋 3.1.3左右双旋 3.1.4右左双旋 总结 引子&#xff1a;AVL树是因…

【单片机】单片机的核心思想

&#x1f4ac;推荐一款模拟面试、刷题神器 、从基础到大厂面试题&#xff1a;&#x1f449;点击跳转刷题网站进行注册学习 目录 一、单片机的核心思想 二、单片机核心图 三、上拉电路及应用 排阻的优势 四、单片机的输入输出模式 1、接收外部电压信号 2、向外输出电压信…

0089 时间复杂度,冒泡排序

/* * 排序也称排序算法&#xff08;Sort Algorithm&#xff09; * 排序是将一组数据&#xff0c;依指定的顺序进行排列的过程。 * * 排序分类 * 1.内部排序&#xff1a;将需要处理的所有数据都加载到内存存储器中进行排序&#xff08;使用内存&#xff09; * 插…

彻底搞懂WeakMap和Map

一 、Map Map是一种叫做字典的数据结构&#xff0c;Map 对象保存不重复键值对&#xff0c;并且能够记住键的原始插入顺序 Map的属性和方法* 属性&#xff1a; size&#xff1a; 返回所包含的键值对长度* 操作方法&#xff1a;* set(key,val): 添加新键值对* get(key): 通过传…

Linux--信号signal、父子进程、SIGCHLD信号相关命令

目录 1.概念&#xff1a; 2.信号的存储位置&#xff1a; 3.常见的信号的值以及对应的功能说明&#xff1a; 4.信号的值在系统源码中的定义&#xff1a; 5.响应方式&#xff1a; 6.改变信号的相应方式&#xff1a; (1)设置信号的响应方式: (2)默认:SIG_DFL;忽略:SIG_IGN…

Android Studio 新版本 Logcat 的使用

前言 最近&#xff0c;Android Studio 自动更新了自带的 Logcat 工具&#xff0c;整体外观和使用方法变得和之前完全不同了。一开始我以为是自己按到什么不该按的按钮&#xff0c;把 Logcat 弄坏了&#xff0c;后来才知道是版本更新导致的。新版本的 Logcat 用命令来过滤信息&…

jmeter变量函数以及抓包用法

抓包 代理服务器&#xff1a; 自己启动一个代理服务器 本地&#xff0c;要使用代理服务器的ip和端口&#xff0c;使用自己启动的代理服务器 操作步骤 添加线程组测试计划 > 非测试元件 > http代理服务器一定要修改 修改为** 测试计划>线程 ip就是你自己电脑的ip&…