Netty4.x实战(一) 基础篇

Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
官方原文

Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers & clients.

Netty 是一个基于NIO的客户-服务器端编程框架,使用Netty 可以确保你快速、简单的开发出一个网络应用,例如实现了某种协议的客户-服务端应用。Netty极大程度的简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
官方原文

Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.

Netty通信模型

Netty的特性

设计

  • 统一的API,适用于不同的协议(阻塞和非阻塞)
  • 基于灵活、可扩展的事件驱动模型
  • 高度可定制的线程模型
  • 可靠的无连接数据Socket支持(UDP)

易用

  • 完善的JavaDoc,用户指南和示例代码
  • 无额外依赖,仅仅依赖 JDK 5 (Netty 3.x) or JDK6 (Netty 4.x)

性能

  • 更好的吞吐量,低延迟
  • 更省资源
  • 尽量减少不必要的内存拷贝

安全

  • 完整的SSL/TLS和STARTTLS支持


简单的hello world程序

了解了Netty的基本概念之后,通过一个简单的sample来了解如何使用Netty提供的API构建自己的应用程序。
1.开发环境

  • JDK 1.7 or higher
  • Eclipse Juno
  • Maven 3.3

2.添加Maven依赖

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

在作者写作本文时,Maven中央仓库中Netty 最新版本为5.0.0.Alpha2,release版本为4.0.34.Final,故后期所有Netty版本皆使用4.0.34.Final版本。

3.server端

HelloWorldServer.java

package com.ricky.codelab.netty.ch1;

import com.ricky.codelab.netty.util.Constant;

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 io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/** * Hello world Server. * @author Ricky * */
public class HelloWorldServer {
    private int port;

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

    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3)
                    .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new StringEncoder(), new StringDecoder(), new HelloWorldServerHandler());
                        }
                    });

            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync(); // (7)

            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to
            // gracefully
            // shut down your server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {

        new HelloWorldServer(Constant.PORT).run();
    }
}

HelloWorldServerHandler.java

package com.ricky.codelab.netty.ch1;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/** * Handles a server-side channel. */
public class HelloWorldServerHandler extends ChannelInboundHandlerAdapter { // (1)

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)

        System.out.println("server receive:"+msg);
        ctx.writeAndFlush("Hello [from server]");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

4.client端

HelloWorldClient.java

package com.ricky.codelab.netty.ch1;

import com.ricky.codelab.netty.util.Constant;

import io.netty.bootstrap.Bootstrap;
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.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/** * Hello world Client. * @author Ricky * */
public class HelloWorldClient {
    private String host;
    private int port;

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

    public void send() throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap();
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        try {
            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new StringEncoder(), new StringDecoder(), new HelloWorldClientHandler());
                        }
                    });

            ChannelFuture future = bootstrap.connect(host, port).sync();

            future.channel().closeFuture().sync();
        } finally {
            eventLoopGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {

        new HelloWorldClient(Constant.HOST, Constant.PORT).send();
    }
}

HelloWorldClientHandler.java

package com.ricky.codelab.netty.ch1;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/** * Handles a client-side channel. */
public class HelloWorldClientHandler extends ChannelInboundHandlerAdapter { // (1)

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // Send the message to Server
        super.channelActive(ctx);
        System.out.println("client send message");
        ctx.writeAndFlush("Hello world![from client]");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)

        System.out.println("client receive:" + msg);
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

在Netty中通信都是基于流来传递的,即以byte的形式传递。所以,我们需要将需要传递的String转换成byte数组。
在Netty4中提供了StringEncoder和StringDecoder来达到这一目的,类似的还有ObjectEncoder和ObjectDecoder来将Object转换为byte数组。

运行程序

先启动HelloWorldServer.java,然后启动HelloWorldClient.java,此时在控制台就能看到打印的输出了。

源代码下载

上述源代码均已上传到GitHub,需要下载源代码的童鞋点此进行下载。

你可能感兴趣的:(netty,nio)