netty4 Android和服务器进行通信

来源:互联网 发布:not close json text 编辑:程序博客网 时间:2024/04/28 19:03

原本公司用的是极光推送消息。但是由于公司网络原因,或者说是极光推送的不及时性,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

0 0
原创粉丝点击