netty构建一个简单的C/S程序

构建一个简单的socket程序

这里采用的是空maven项目,构建client端和server端,实现一个客户端建立连接后发送消息,然后服务端返回一个消息的简单程序

server端代码

基本套路:

  1. 在Server类中创建分发线程组和工作线程组,创建启动类Bootstrap服务端是ServerBootstrap)
  2. 为Bootstrap进行初始化,指定channel,初始化channel(初始化channel有两个函数,一个是childHandler,还有个是handler,其中childHandler对应的是工作线程组)
  3. 编写初始化channel的类,装填handler在管道中。(这里我把channel初始化类卸载Server类中了,使用了匿名内部类创建并初始化)
  4. 编写业务handler

Server类代码:

public class Server {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();//分发线程组
        EventLoopGroup workerGroup = new NioEventLoopGroup();//工作线程组
        ServerBootstrap cb = new ServerBootstrap();//服务启动对象
        try {
            //这里直接用匿名内部类构造channel初始化类
            //绑定线程组,设置channel,初始化channel
            cb.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();//初始化管道
                    pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4))
                            .addLast(new LengthFieldPrepender(4))
                            .addLast(new StringDecoder())
                            .addLast(new StringEncoder())
                            .addLast(new ServerHandler());//最后执行我们的业务handler
                }
            });
            ChannelFuture channelFuture = cb.bind( 9999).sync();//绑定端口
            channelFuture.channel().closeFuture().sync();//关闭
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();//优雅关闭
            workerGroup.shutdownGracefully();//优雅关闭
        }
    }
}

handler代码:

public class ServerHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        //等待五秒后发送给客户端消息
        Thread.sleep(5000);
        System.out.println(ctx.channel().remoteAddress()+":"+msg);
        ctx.writeAndFlush("服务端端回复");
    }

    //处理异常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();//遇到异常关闭连接
    }
}

client端代码

client端代码和server端代码很相似,这也是源于netty的巧妙设计,很强大
client端的server代码:

public class ClientServer {
    public static void main(String[] args) {
        EventLoopGroup group = new NioEventLoopGroup();//客户端不需要分发线程,所以只需要一个线程组就行了
        Bootstrap cb = new Bootstrap();//这里不再使用ServerBootstrap了,因为是客户端
        try {
            //这里直接用匿名内部类构造channel初始化类
            //同样这里的channel对象,用的也不是NioServerSocketChannel进行反射构造了。因为只有一个线程组就使用了handler
            cb.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4))
                            .addLast(new LengthFieldPrepender(4))
                            .addLast(new StringDecoder())
                            .addLast(new StringEncoder())
                            .addLast(new ClientHandler());//这里基本上和服务端一样
                }
            });
            ChannelFuture channelFuture = cb.connect("localhost", 9999).sync();
            channelFuture.channel().writeAndFlush("hello");//这里是手动发送消息,其实还可以通过handler中的回调触发发送消息
            channelFuture.channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}

handler代码:

public class ClientHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(ctx.channel().remoteAddress()+":"+msg);//显示服务端的消息
        ctx.writeAndFlush("客户端回复");//然后再回复,这里就会不断的相互发送消息,因为服务端也会回复,互相发送
    }

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

运行结果

先启动server再启动client,查看结果
Server端
netty构建一个简单的C/S程序
Client端
netty构建一个简单的C/S程序

总结

可以看出netty不仅对服务端有很好的封装,相应的对于服务端也能同样的套路编写。方便了我们使用底层的网络编程API,netty的设计理念只是为了提供一个更好的使用底层网络编程的框架,可以供我们做更多的上层搭建。
通过之前的基于Http协议的程序和现在的C/S模式的程序,也能看出,这其中变化最大的部分应该是对channel初始化的配置,其中很多都是使用netty提供好的handler进行管道的配置,能让我们更容易的解析socket中传输的数据,这将会是使用netty的重点学习部分。

netty构建一个简单的C/S程序

上一篇:PHP设计模式之命令模式


下一篇:Python 2.7 cython cythonize py 编译成 pyd 谈谈那些坑