netty4 Android和服务器进行通信

原本公司用的是极光推送消息。但是由于公司网络原因,或者说是极光推送的不及时性,BOSS说太慢,就让改成长链接了,花费了几天时间查资料,总算搞懂了一点皮毛,简单的通讯已经不是问题了。今天下午无事,写点内容巩固写记忆。我负责的Android这边。所以服务器的那边的不太会。netty的版本是netty-4.0.31.Final。。

一。服务端代码

这里是主要代码。NettyServerHandler()方法主要是进行发送消息和接受消息的操作。

public class NettyServerBootstrap {
    private int port;
    public NettyServerBootstrap(int port) throws InterruptedException {
        this.port = port;
        bind();
    }

    private void bind() throws InterruptedException {
        EventLoopGroup boss=new NioEventLoopGroup();
        EventLoopGroup worker=new NioEventLoopGroup();
        ServerBootstrap bootstrap=new ServerBootstrap();
        bootstrap.group(boss,worker);
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.option(ChannelOption.SO_BACKLOG, 128);
        //通过NoDelay禁用Nagle,使消息立即发出去,不用等待到一定的数据量才发出去
        bootstrap.option(ChannelOption.TCP_NODELAY, true);
        //保持长连接状态
        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                ChannelPipeline p = socketChannel.pipeline();
               /* p.addLast(new ObjectEncoder());
                p.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));*/
                p.addLast(new NettyServerHandler());
            }
        });
        ChannelFuture f= bootstrap.bind(port).sync();
        if(f.isSuccess()){
            System.out.println("server start---------------");
        }
    }

    //开启服务器端口监听
    public static void main(String []args) throws InterruptedException {
        NettyServerBootstrap bootstrap=new NettyServerBootstrap(9999);
        /*while (true){
            SocketChannel channel=(SocketChannel)NettyChannelMap.get("001");
            if(channel!=null){
                AskMsg askMsg=new AskMsg();
                channel.writeAndFlush(askMsg);
            }
            TimeUnit.SECONDS.sleep(5);
        }*/
    }
}

服务端代码2。

public class NettyServerHandler extends SimpleChannelInboundHandler<Object> {
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //channel失效,从Map中移除
        NettyChannelMap.remove((SocketChannel)ctx.channel());
    }
    //这里是从客户端过来的消息
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object baseMsg) throws Exception {
        System.out.println("收到没有");
        //传送的消息是ByteBuf格式的。所以不管发送还是接收都需要转化
        String msg1=((ByteBuf)baseMsg).toString(CharsetUtil.UTF_8).trim();
        System.out.println(msg1);
        //ReferenceCountUtil.release(baseMsg);
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {
        super.exceptionCaught(ctx, cause);
        System.out.println("出现异常了。");
    }
}
二。客户端代码

客户端代码和服务端基本属于一样的结构。

public class NettyClientBootstrap {
    private int port=9999;
    private String host="192.168.1.186";
    public SocketChannel socketChannel;
    public  void startNetty() throws InterruptedException {
        System.out.println("长链接开始");
        if(start()){
            System.out.println("长链接成功");
            ByteBuf bb = Unpooled.wrappedBuffer(("tableIP=asdf".getBytes(CharsetUtil.UTF_8)));
            socketChannel.writeAndFlush(bb);
        }
    }
    private Boolean start() throws InterruptedException {
        EventLoopGroup eventLoopGroup=new NioEventLoopGroup();
        Bootstrap bootstrap=new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.SO_KEEPALIVE,true);
        bootstrap.group(eventLoopGroup);
        bootstrap.remoteAddress(host, port);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                socketChannel.pipeline().addLast(new IdleStateHandler(20, 10, 0));
                //下面注释的两行是加密和解密。服务器和客户端需要统一
                //不然会报错。所以我直接注释了。
                /*socketChannel.pipeline().addLast(new ObjectEncoder());
                socketChannel.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));*/
                socketChannel.pipeline().addLast(new NettyClientHandler());
            }
        });
        ChannelFuture future = null ;
        try {
            future =bootstrap.connect(new InetSocketAddress(host,port)).sync();
            if (future.isSuccess()) {
                socketChannel = (SocketChannel)future.channel();
                System.out.println("connect server  成功---------");
                return true;
            }else{
                System.out.println("connect server  失败---------");
                startNetty();
                return false;
            }
        } catch (Exception e) {
            System.out.println("无法连接----------------");
            //这里最好暂停一下。不然会基本属于毫秒时间内执行很多次。
            //造成重连失败
            TimeUnit.SECONDS.sleep(5);
            startNetty();
            return false;
        }
    }
}
public class NettyClientHandler extends SimpleChannelInboundHandler<Object> {
    //设置心跳时间  开始
    public static final int MIN_CLICK_DELAY_TIME = 1000*30;
    private long lastClickTime =0;
    //设置心跳时间   结束

    //利用写空闲发送心跳检测消息
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            switch (e.state()) {
                case WRITER_IDLE:
                     long currentTime = System.currentTimeMillis();
                     if(currentTime - lastClickTime > MIN_CLICK_DELAY_TIME){
                         lastClickTime = System.currentTimeMillis();
                         ByteBuf bb = Unpooled.wrappedBuffer("ping".getBytes(CharsetUtil.UTF_8));
                         ctx.writeAndFlush(bb);
                         System.out.println("send ping to server----------");
                     }
                    break;
                default:
                    break;
            }
        }
    }
    //这里是接受服务端发送过来的消息
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object baseMsg) throws Exception {
        String msg1=((ByteBuf)baseMsg).toString(CharsetUtil.UTF_8).trim();
        System.out.println("1111111111111111------------------------"+msg1);
        ReferenceCountUtil.release(msg1);
    }
    NettyClientBootstrap nettyClient=new NettyClientBootstrap();

    //这里是断线要进行的操作
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        System.out.println("重连了。---------");
        //这里最好暂停一下。不然会基本属于毫秒时间内执行很多次。
        //造成重连失败
        TimeUnit.SECONDS.sleep(5);
        nettyClient.startNetty();
        //ctx.channel().eventLoop().schedule();
    }
    //这里是出现异常的话要进行的操作
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {
        super.exceptionCaught(ctx, cause);
        System.out.println("出现异常了。。。。。。。。。。。。。");
        TimeUnit.SECONDS.sleep(10);
        nettyClient.startNetty(context);
        cause.printStackTrace();
    }
}

这里的代码就是简单启动一下长链接。。

public class MainActivity extends Activity {
    private Button sendButton;

    NettyClientBootstrap nettyStart=new NettyClientBootstrap();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sendButton = (Button) findViewById(R.id.btn1);
        sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    nettyStart.startNetty();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

    }
}

这里是运行效果。。
服务端开启
客户端开启
服务端收到消息
服务端收到心跳
客户端30S发送心跳
最后加上代码下载链接。还有一份java客户端的。不过是很简单的。
http://download.csdn.net/detail/a466125796/9149831

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值