【Netty】写个echo服务器与客户端

自定义Handler:

handle是用来处理消息的。

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
// #1
@Sharable
// #2
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
	// #3
    @Override
    public void channelRead(ChannelHandlerContext context, Object msg) {
        ByteBuf in = (ByteBuf) msg;
        System.out.println( "Server received: " + in.toString( CharsetUtil.UTF_8 ) );
        // #4
        context.write( in );
        // #5
        context.flush();
    }
	// #6
    @Override
    public void exceptionCaught(ChannelHandlerContext context, Throwable cause) {
        cause.printStackTrace();
        context.close();
    }
}

  1. @sharable注解标注一个channel handler可以被多个channel安全地共享。
  2. 继承自ChannelInboundHandlerAdapter类。
  3. 重写父类channelRead()方法,每当从收到新的数据时,这个方法会在收到消息时被调用,这个例子中,收到的消息的类型是 ByteBuf。
  4. 将收到的数据写入到ChannelOutboundBuffer中。
  5. 将数据从ChannelOutboundBuffer中flush到套接字的发送缓冲区中。
  6. 捕获异常的

自定义Initializer

Initializer是用来加载Handler到pipe中的。

import io.netty.channel.Channel;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
// #1
public class CustomServerInitializer extends ChannelInitializer {
    private ChannelInboundHandlerAdapter handlerAdapter;

    public CustomServerInitializer(ChannelInboundHandlerAdapter handlerAdapter) {
        this.handlerAdapter = handlerAdapter;
    }
	// #2
    @Override
    protected void initChannel(Channel channel) throws Exception {
    	// 将handle添加到pipe
        channel.pipeline().addLast( handlerAdapter );
    }
}

  1. 继承自ChannelInitializer 类
  2. 重写父类initChannel()方法
  3. 将handle添加到piipe中

服务端

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;

import java.net.InetSocketAddress;

public class EchoServer {
	// #1
    private final int port;

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

    public void start() throws Exception {
    	// #2
        final EchoServerHandler serverHandler = new EchoServerHandler();
        // #3
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        try {
        	// #4
            ServerBootstrap bootstrap = new ServerBootstrap();
            // #5 
            ChannelFuture future = bootstrap.group( boss,worker )
                    // #6
                    .channel( NioServerSocketChannel.class )
                    // #7
                    .localAddress( new InetSocketAddress( port ) )
                    // #8
                    .childHandler( new CustomServerInitializer( serverHandler ) 
                    .bind()
                    .sync();
            future.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully().sync();
        }
    }
}

  1. 端口
  2. 实例化自定义的handle
  3. NioEventLoopGroup 是用来处理I/O操作的多线程事件循环器。
    在这个例子中我们实现了一个服务端的应用,因此会有2个 NioEventLoopGroup 会被使用。第一个经常被叫做‘boss’,用来接收进来的连接。第二个经常被叫做‘worker’,用来处理已经被接收的连接,一旦‘boss’接收到连接,就会把连接信息注册到‘worker’上。
  4. 辅助启动类
  5. 设置事件循环器。
  6. 指定通道channel的类型,由于是服务端,故而是NioServerSocketChannel。
  7. 绑定端口
  8. 实例化自定义的Initializer,并将自定义的handle对象传进去。

自定义Handler:

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;

import static io.netty.channel.ChannelHandler.Sharable;

@Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    @Override
    public void channelActive(ChannelHandlerContext context) {
        context.writeAndFlush( Unpooled.copiedBuffer( "Netty rocks!", CharsetUtil.UTF_8 ) );
    }

    @Override
    public void channelRead0(ChannelHandlerContext context, ByteBuf in) {
        System.out.println( "Client received: " + in.toString( CharsetUtil.UTF_8 ) );
    }

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

自定义Initializer

import io.netty.channel.Channel;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;

public class CustomClientInitializer extends ChannelInitializer {
    private ChannelInboundHandlerAdapter handlerAdapter;

    public CustomClientInitializer(ChannelInboundHandlerAdapter handlerAdapter) {
        this.handlerAdapter = handlerAdapter;
    }

    @Override
    protected void initChannel(Channel channel) throws Exception {
        channel.pipeline().addLast( handlerAdapter );
    }
}

客户端

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 EchoClient {
    private final String host;
    private final int port;

    public EchoClient(String host, int port) {
        this.host = host;
        this.port = port;
    }
    public void start() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            ChannelFuture future = bootstrap.group( group )
                    .channel( NioSocketChannel.class )
                    .remoteAddress( new InetSocketAddress( host, port ) )
                    .handler( new CustomClientInitializer( new EchoClientHandler() ) )
                    .connect()
                    .sync();
            future.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully().sync();
        }
    }
}

你可能感兴趣的:(Java,——Netty)