Netty写的Echo 服务器的例子

1. Netty写的Echo服务器

  1. 项目结构与依赖
    • 确保已经正确设置了开发环境,包括JDK、IDE和Apache Maven。
    • 在Maven项目中,需要添加Netty的依赖,以下是一个简单的POM配置示例:
      <dependencies>
          <dependency>
              <groupId>io.netty</groupId>
              <artifactId>netty-all</artifactId>
              <version>4.1.90.Final</version> <!-- 请根据实际版本号修改 -->
          </dependency>
      </dependencies>
      
  2. 服务器代码实现
    • 创建EchoServerHandler类
      import io.netty.buffer.ByteBuf;
      import io.netty.channel.ChannelHandlerContext;
      import io.netty.channel.ChannelInboundHandlerAdapter;
      
      public class EchoServerHandler extends ChannelInboundHandlerAdapter {
          @Override
          public void channelRead(ChannelHandlerContext ctx, Object msg) {
              // 处理接收到的消息
              ByteBuf in = (ByteBuf) msg;
              System.out.println("Server received: " + in.toString(io.netty.util.CharsetUtil.UTF_8));
      
              // 将接收到的消息写回给客户端
              ctx.write(in);
          }
      
          @Override
          public void channelReadComplete(ChannelHandlerContext ctx) {
              // 当所有数据都被读取完成后,刷新缓冲区并关闭连接
              ctx.writeAndFlush(io.netty.buffer.Unpooled.EMPTY_BUFFER)
                    .addListener(ChannelFutureListener.CLOSE);
          }
      
          @Override
          public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
              // 处理异常
              cause.printStackTrace();
              ctx.close();
          }
      }
      
      • channelRead方法:当从客户端接收到消息时,会调用这个方法。它将接收到的消息转换为ByteBuf对象,并打印出来。然后,将消息写回给客户端。
      • channelReadComplete方法:当所有数据都被读取完成后,会调用这个方法。它使用writeAndFlush方法将一个空的ByteBuf写回给客户端,并添加一个ChannelFutureListener,当写操作完成后,关闭连接。
      • exceptionCaught方法:当在处理过程中发生异常时,会调用这个方法。它打印异常的堆栈跟踪信息,并关闭连接。
    • 创建EchoServer类
      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;
      
      public class EchoServer {
          private final int port;
      
          public EchoServer(int port) {
              this.port = port;
          }
      
          public static void main(String[] args) throws Exception {
              if (args.length!= 1) {
                  System.err.println("Usage: EchoServer <port>");
                  System.exit(1);
              }
      
              int port = Integer.parseInt(args[0]);
              new EchoServer(port).start();
          }
      
          public void start() throws Exception {
              // 创建EventLoopGroup,用于处理网络事件
              EventLoopGroup group = new NioEventLoopGroup();
              try {
                  // 创建ServerBootstrap,用于引导服务器启动
                  ServerBootstrap bootstrap = new ServerBootstrap();
                  bootstrap.group(group)
                        .channel(NioServerSocketChannel.class)
                        .localAddress(new io.netty.socket.InetSocketAddress(port))
                        .childHandler(new ChannelInitializer<io.netty.channel.socket.nio.SocketChannel>() {
                              @Override
                              protected void initChannel(io.netty.channel.socket.nio.SocketChannel ch) throws Exception {
                                  // 将EchoServerHandler添加到ChannelPipeline中
                                  ch.pipeline().addLast(new EchoServerHandler());
                              }
                          });
      
                  // 绑定服务器,并等待绑定完成
                  ChannelFuture future = bootstrap.bind().sync();
      
                  // 等待服务器关闭
                  future.channel().closeFuture().sync();
              } finally {
                  // 关闭EventLoopGroup,释放资源
                  group.shutdownGracefully().sync();
              }
          }
      }
      
      • 构造函数:初始化Echo服务器,指定服务器要监听的端口。
      • main方法:程序的入口点,解析命令行参数,创建EchoServer实例,并调用start方法启动服务器。
      • start方法
        • 创建EventLoopGroup:使用NioEventLoopGroup创建一个事件循环组,用于处理网络事件。
        • 创建ServerBootstrap:使用ServerBootstrap引导服务器启动,设置事件循环组、Channel类型和本地地址。
        • 设置ChildHandler:通过childHandler方法设置一个ChannelInitializer,用于初始化每个新连接的ChannelPipeline。在initChannel方法中,将EchoServerHandler添加到ChannelPipeline中,以处理客户端的消息。
        • 绑定服务器并等待完成:使用bind方法绑定服务器到指定的端口,并使用sync方法阻塞当前线程,直到绑定完成。
        • 等待服务器关闭:通过future.channel().closeFuture().sync()方法等待服务器关闭,当服务器的Channel关闭时,这个Future会完成。
        • 关闭EventLoopGroup:在服务器关闭后,使用group.shutdownGracefully().sync()方法关闭EventLoopGroup,释放资源。
  3. 运行示例
    • 编译和运行代码:可以使用Maven命令mvn clean package编译项目,然后使用java -jar target/echo-server-1.0-SNAPSHOT.jar <port>运行服务器,其中<port>是服务器要监听的端口号。
    • 测试功能:可以使用Netty提供的Telnet客户端或者其他网络工具来连接到服务器,并发送一些消息。服务器会接收到这些消息,并将它们回送给客户端。

以下是一个使用Telnet客户端测试Echo服务器的示例:

  • 打开终端
    • 在命令行中输入telnet localhost <port>,其中<port>是服务器监听的端口号。
  • 发送消息
    • 连接成功后,可以在终端中输入一些消息,然后按下回车键。服务器会接收到这些消息,并将它们回送给客户端。
  • 关闭连接
    • 在终端中输入quit命令,然后按下回车键,关闭与服务器的连接。

通过以上步骤,就可以使用Netty实现一个简单的Echo服务器,并进行测试。这个例子展示了Netty的基本使用方法,包括如何创建服务器、处理客户端连接和消息、以及如何关闭服务器。

2. 服务器端组件使用

2.1 EventLoopGroup
  • 创建:在EchoServer类的start方法中,使用NioEventLoopGroup创建一个事件循环组,用于处理网络事件。
EventLoopGroup group = new NioEventLoopGroup();
  • 作用:它是Netty的核心组件之一,用于处理网络连接的接受、数据的读取和写入等I/O操作。一个NioEventLoopGroup包含一个或多个NioEventLoop,每个NioEventLoop都有自己的线程,可以并发地处理多个网络连接。
2.2 ServerBootstrap
  • 创建与配置:在start方法中创建ServerBootstrap实例,并进行一系列配置。
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(group)
     .channel(io.netty.channel.nio.NioServerSocketChannel.class)
     .localAddress(new io.netty.socket.InetSocketAddress(port))
     .childHandler(new ChannelInitializer<io.netty.channel.socket.nio.SocketChannel>() {
            @Override
            protected void initChannel(io.netty.channel.socket.nio.SocketChannel ch) throws Exception {
                // 将EchoServerHandler添加到ChannelPipeline中
                ch.pipeline().addLast(new EchoServerHandler());
            }
        });
  • group方法:设置用于处理服务器端套接字的EventLoopGroup
  • channel方法:指定服务器使用的Channel类型,这里使用NioServerSocketChannel,它是基于NIO的服务器套接字通道实现。
  • localAddress方法:设置服务器要监听的本地地址和端口。
  • childHandler方法:设置一个ChannelInitializer,用于初始化每个新连接的SocketChannel。在initChannel方法中,将自定义的EchoServerHandler添加到ChannelPipeline中。
2.3 ChannelPipeline与ChannelHandler
  • ChannelPipeline:它是一个处理管道,用于组织和处理流经Channel的数据。当数据在Channel中流动时,会依次经过ChannelPipeline中的各个ChannelHandler
  • ChannelHandler:在这个例子中,自定义了EchoServerHandler类,它继承自ChannelInboundHandlerAdapter,用于处理客户端连接的入站数据。
    • channelRead方法:当从客户端接收到消息时,会调用这个方法。它将接收到的消息转换为ByteBuf对象,并打印出来,然后将消息写回给客户端。
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf in = (ByteBuf) msg;
        System.out.println("Server received: " + in.toString(io.netty.util.CharsetUtil.UTF_8));
        ctx.write(in);
    }
    
    • channelReadComplete方法:当所有数据都被读取完成后,会调用这个方法。它使用writeAndFlush方法将一个空的ByteBuf写回给客户端,并添加一个ChannelFutureListener,当写操作完成后,关闭连接。
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.writeAndFlush(io.netty.buffer.Unpooled.EMPTY_BUFFER)
             .addListener(ChannelFutureListener.CLOSE);
    }
    
    • exceptionCaught方法:当在处理过程中发生异常时,会调用这个方法。它打印异常的堆栈跟踪信息,并关闭连接。
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
    

3. 启动与关闭服务器

  • 启动服务器:在start方法中,使用bind方法绑定服务器到指定的端口,并使用sync方法阻塞当前线程,直到绑定完成。
ChannelFuture future = bootstrap.bind().sync();
  • 等待服务器关闭:通过future.channel().closeFuture().sync()方法等待服务器关闭,当服务器的Channel关闭时,这个Future会完成。
  • 关闭EventLoopGroup:在服务器关闭后,使用group.shutdownGracefully().sync()方法关闭EventLoopGroup,释放资源。
好的,我可以回答您的问题。Netty是一个开源的Java NIO框架,它可以用来开发高性能、高可靠性的网络服务器和客户端。下面是一个使用NettyHTTP服务器的示例代码: ``` import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; 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 io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.stream.ChunkedWriteHandler; public class HttpServer { private final int port; public HttpServer(int port) { this.port = port; } public void start() throws InterruptedException { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast("codec", new HttpServerCodec()); ch.pipeline().addLast("aggregator", new HttpObjectAggregator(512 * 1024)); ch.pipeline().addLast("chunked", new ChunkedWriteHandler()); ch.pipeline().addLast("handler", new HttpServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { HttpServer server = new HttpServer(8080); server.start(); } } ``` 这段代码创建了一个HTTP服务器,监听来自客户端的请求。其中,HttpServerCodec用于将HTTP请求和响应消息编码和解码,HttpObjectAggregator用于将HTTP请求和响应的多个部分合并成一个完整的HTTP消息,ChunkedWriteHandler用于处理HTTP消息的大文件和流数据。 在这个示例中,我们使用了Netty的NIO事件循环组。我们创建了两个事件循环组:一个用于处理传入的连接请求,一个用于处理连接请求后的I/O操作。 这是使用NettyHTTP服务器的基础,您可以根据您的具体需求进行更改和定制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值