Netty实战(二)Netty服务器,采用Protobuf编解码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29461259/article/details/75207786

2.1 准备工作创建工程

  • 创建一个工程包含服务端和客户端两个Module

  • 修改上篇文章提到过的BaseMsg.proto文件中,定义的包名

  • 运行gen.bat程序,生成对应的类

  • 把生成好的类,拷贝到对应的包名下

关系图

  • 工程中,添加protobuf和netty的jar包

依赖的jar包

2.2服务端代码思路

  1. 通过ServerBootstrap,快速构建服务端代码

  2. 服务端消息编解码方式采用protobuf

2.3消息编解码的 配置(服务端和客户端通用)

采用protobuf编解码

2.4 NettyServerBootstrap,负责启动服务端程序

package com.netty.test;
import com.netty.test.pojo.BaseMsgOuterClass;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

public class NettyServerBootstrap {

    public EventLoopGroup boss;
    public EventLoopGroup worker;

    private void bind(int port) {
        //配置服务器端的NIO线程组
        boss = new NioEventLoopGroup();
        worker = new NioEventLoopGroup();

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(boss, worker);
        bootstrap.channel(NioServerSocketChannel.class);

        bootstrap.option(ChannelOption.*SO_BACKLOG*, 1024 * 100);
        bootstrap.option(ChannelOption.*TCP_NODELAY*, true);
        bootstrap.childOption(ChannelOption.*SO_KEEPALIVE*, true);

        //初始化channel,添加解码器,防止TCP拆包粘包问题
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                ChannelPipeline p = socketChannel.pipeline();

                //1.消息解码
                p.addLast(new ProtobufVarint32FrameDecoder());
                //需要解码的目标类
                p.addLast( new ProtobufDecoder(BaseMsgOuterClass.BaseMsg.*getDefaultInstance*()));

                //2.消息的编码
                p.addLast(new ProtobufVarint32LengthFieldPrepender());
                p.addLast(new ProtobufEncoder());

                p.addLast(serverHandler);
            }
        });

        try {
            ChannelFuture f = bootstrap.bind(port).sync();

            if (f.isSuccess()) {
                System.*out*.println("server start---------------");
            } else {
                System.*out*.println("server start-------failure--------");

            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private NettyServerHandler serverHandler;

    public void start(int port) throws InterruptedException {

        serverHandler = new NettyServerHandler( );
        bind(port);
    }

}

 ```

###2.5 NettyServerHandler,负责接收客户端传来的消息

```java
package com.netty.test;

import android.content.Context;

import com.netty.test.pojo.BaseMsgOuterClass;

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

*/**
 * Created by pengfei on 2017/5/11.
 */

*//加上此注解,每次新的客户端连接进来的时候不用重新再new一个handler了,
@ChannelHandler.Sharable
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    public Context mContext;

    public NettyServerHandler() {
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);

    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        if (msg instanceof BaseMsgOuterClass.BaseMsg) {

            BaseMsgOuterClass.BaseMsg baseMsg = (BaseMsgOuterClass.BaseMsg) msg;

            String msgType = baseMsg.getMsgType();
            System.*out*.print("消息的类型:"+msgType);

            //BaseMsg.proto的消息内容为bytes类型的,它是二进制的。
            //这样我们可以根据需要,把消息内容解码为文本消息,或文件消息
            String msgContent = baseMsg.getMsg().toStringUtf8();
            System.*out*.print("消息的内容:"+msgContent);
        }

    }

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

}

最后,有兴趣的可以关注下方的公众号,会定期分享一些知识,以及工作中所遇到问题的解决方案。扫描二维码就可以添加关注:

猜你喜欢

转载自blog.csdn.net/qq_29461259/article/details/75207786
今日推荐