Netty初步——搭建一个Netty程序

本文介绍Netty框架的基本使用,包括客户端和服务端的建立过程,以及关键组件如EventLoopGroup、Channel和ChannelHandler的作用。通过实例演示了如何创建Netty应用程序,并强调了编码解码的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    Netty是一款用于快速开发高性能的网络应用程序的Java框架,是一个异步事件驱动的网络应用框架。

导入依赖

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

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

创建一个Netty程序

1. ClientHandle
public class ClientHandle extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {
        System.out.println("客户端已激活");
        channelHandlerContext.writeAndFlush("Hello world");
    }

    @Override
    public void channelInactive(ChannelHandlerContext channelHandlerContext) throws Exception {
        System.out.println("客户端已关闭");
    }

    @Override
    public void channelRead(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
        System.out.println("发送消息");

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
        throwable.printStackTrace();
        channelHandlerContext.channel().close();
    }

}
2. Client
public class Client {
    private int port;
    private String ip;

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

    public void start(){
        EventLoopGroup eventExecutors=new NioEventLoopGroup();
        Bootstrap bootstrap=new Bootstrap();
        bootstrap.group(eventExecutors)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline channelPipeline=socketChannel.pipeline();
                        channelPipeline.addLast("decoder", new StringDecoder());
                        channelPipeline.addLast("encoder", new StringEncoder());
                        channelPipeline.addLast(new ClientHandle());
                    }
                });
        try {
            ChannelFuture channelFuture=bootstrap.connect("127.0.0.1",9999).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
3. ServerHandle
public class ServerHandle extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {
        System.out.println("服务端已激活");
    }

    @Override
    public void channelInactive(ChannelHandlerContext channelHandlerContext) throws Exception {
        System.out.println("服务端已关闭");
    }

    @Override
    public void channelRead(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
        System.out.println("接收到从客户端"+channelHandlerContext.channel().remoteAddress()+"的消息:"+o.toString());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
        throwable.printStackTrace();
        channelHandlerContext.channel().close();
    }
}
4. Server
public class Server {
    private int port;
    //private String ip;

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

    public void start(){
        EventLoopGroup listerloopGroup=new NioEventLoopGroup();
        EventLoopGroup workLoopGroup=new NioEventLoopGroup();
        ServerBootstrap serverBootstrap=new ServerBootstrap();
        serverBootstrap.group(listerloopGroup,workLoopGroup)
                .channel(NioServerSocketChannel.class)
                .localAddress(port)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline channelPipeline=socketChannel.pipeline();
                        channelPipeline.addLast("decoder", new StringDecoder());
                        channelPipeline.addLast("encoder", new StringEncoder());
                        channelPipeline.addLast(new ServerHandle());
                    }
                });
        try {
            ChannelFuture channelFuture=serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

上述程序表示了客户端连到服务端时,客户端向服务端发送一条Hello world的信息。

组件初解

  • EventLoopGroup、EventLoop、Channel
  1. EventLoopGroup为Netty的事件循环组,里面包含了多个EventLoop,服务端一般具有两个事件循环组,一个用于监听新的连接,另外一个来处理已连接的客户端,当然也可以使用一个,那么这两者都在一个事件循环组里进行。

  2. 每个EventLoop代表着一个线程,用来处理其绑定的Channel的所有事件,且每个EventLoop可以被绑定多个Channel。

  • ChannelHandlr、ChannelPipline、ChannelHandleContext
  1. 每个Channel都有一条ChannelPipline,每个ChannelPipline里面包括多个ChannelHandle(至少一个)
  2. ChannelHandle用来处理流经Channel的数据,通过ChannelHandleContext将每个ChannelHandle处理的结果连接起来
  • ChannelInboundHandlerAdapter、ChannelOutboundHandlerAdapter
  1. ChannelInboundHandlerAdapter对应着入站事件(读事件、注册事件等),相反ChannelOutboundHandlerAdapter对应着出站事件(写事件等)
  2. 这两者是相对的概念,对服务器来言,服务端写入客户端称之为出站,而对于客户端来言,客户端写入服务器称为出站
  • ServerBootstrap、Bootstrap
  1. ServerBootstrap对应服务端的启动类,而Bootstrap对应着客户端的启动类
  2. 大部分的配置都在启动类上进行的,包括指明传输方式、配置ChannelHandle等
  • childHandler方法、Handle方法
  1. childHandler方法为已被接受的子Channel处理,代表着一个绑定到远程节点的套接字,也就是为每个客户端设置ChannelHandle,用来处理每个客户端除了连接的操作
  2. Handle方法添加的ChannelHandle由ServerChannel处理,代表着为服务端创建新的子Channel并处理,其实就是处理新的客户端连接

注意事项

  1. 传输时必须对消息进行利用解码器与编码器进行编码和解码,否则传输的消息接收不到
  2. 服务端与客户端指定的传输方式必须一致,即服务端指定传输方式为NIO,则客户端也必须使用NIO
### 使用 Netty 框架搭建应用程序 Netty一个基于 Java 的异步事件驱动网络应用框架,主要用于构建高性能、高可扩展性的网络服务器和客户端[^1]。为了使用 Netty 构建应用程序,开发者可以遵循一系列配置和编码实践。 #### 配置环境 首先,在项目中引入 Netty 库是非常重要的一步。可以通过 Maven 或 Gradle 自动化依赖管理工具来简化这一过程;也可以手动下载 jar 文件并将其添加至项目的类路径中。对于后者,需注意的是不仅要将 `netty-all` 版本的 jar 放入 lib 文件夹下,还需通过 IDE 设置使其成为编译路径的一部分,这样才能确保程序能够识别并利用这些库中的类定义和方法实现[^3]。 #### 编写服务端代码 创建一个简单的 TCP 服务器作为例子: ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io⚗📐📐 📐📐📐 import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; public class EchoServer { private final int port; public EchoServer(int port) { this.port = port; } public void start() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap() .group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new StringDecoder()); p.addLast(new StringEncoder()); p.addLast(new EchoServerHandler()); } }); ChannelFuture f = b.bind(port).sync(); System.out.println("Echo server started at " + port); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new EchoServer(8080).start(); } } ``` 这段代码展示了如何启动一个监听指定端口的服务端实例,并设置处理器链以处理传入连接的数据流。这里采用字符串解码器与编码器方便演示消息传递逻辑。 #### 定义业务逻辑处理器 继续上面的例子,还需要编写具体的业务逻辑处理器 `EchoServerHandler` 来响应来自客户端的消息请求: ```java import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; public class EchoServerHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println("Received message from client: " + msg); ctx.writeAndFlush("ECHO: " + msg); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } } ``` 此部分实现了对接收到的信息打印输出以及向发送方回显相同内容的功能。当遇到异常情况时会关闭通道并记录错误日志。 #### 实现公共接口 如果希望进一步抽象出通用的服务层,则可以根据实际需求设计相应的 API 接口。例如下面展示了一个名为 `HelloService` 的简单接口及其可能的一个具体实现方式[^2]: ```java package com.wanshi.netty.dubborpc.publicinterface; /** * 公共接口,提供服务 */ public interface HelloService { String hello(String msg); } // 可能的具体实现之一 class HelloWorldServiceImpl implements HelloService { @Override public String hello(String msg) { return "Hello, " + msg; } } ``` 上述代码片段说明了怎样定义一个用于远程调用的基础契约形式——即声明一组可供外部访问的方法签名而不涉及任何内部细节描述。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值