Netty_Android 使用netty与服务器保持长连接腾讯_android 关机后netty不断-程序员宅基地

技术标签: android  socket通讯  socket  netty  

Netty_Android

项目地址:https://github.com/zhangYanGitHub/Netty_Demo
采用netty-4.1.16.Final 于服务器保持长连接进行通讯
主要思路为: 开启一个service 初始化Netty连接
  • service 类

    private NetworkReceiver receiver;
        public static final String TAG = NettyService.class.getName();
    
        public NettyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            receiver = new NetworkReceiver();
            IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
            LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
    
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            //初始化Netty
            NettyClient.getInstance().setListener(this);
            connect();
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
            NettyClient.getInstance().setReconnectNum(0);
            NettyClient.getInstance().disconnect();
        }
    
        private void connect() {
            if (!NettyClient.getInstance().getConnectStatus()) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        NettyClient.getInstance().connect();//连接服务器
                    }
                }).start();
            }
        }
    
        @Override
        public void onMessageResponse(String messageHolder) {
            notifyData(NettyActivity.MSG_FROM_SERVER, messageHolder);
    
        }
    
        private void notifyData(int type, String messageHolder) {
            final Stack<NettyActivity> activities = ActivityManager.getInstance().getActivities();
            for (NettyActivity activity : activities) {
                if (activity == null || activity.isFinishing()) {
                    continue;
                }
                Message message = Message.obtain();
                message.what = type;
                message.obj = messageHolder;
                activity.getHandler().sendMessage(message);
            }
        }
    
        @Override
        public void onServiceStatusConnectChanged(int statusCode) {
            if (statusCode == NettyListener.STATUS_CONNECT_SUCCESS) {
                Log.e(TAG, "connect sucessful");
                sendAuthor();
            } else {
                Log.e(TAG, "connect fail statusCode = " + statusCode);
                notifyData(NettyActivity.MSG_NET_WORK_ERROR, String.valueOf("服务器连接失败"));
            }
    
        }
    
        /**
         * 连接初始化 认证信息
         * 发送认证信息 这个可以根据项目的实际需要数据类型 进行修改
         */
        private void sendAuthor() {
            final Netty_RegisterInfo nettyRegisterInfo = new Netty_RegisterInfo();
            nettyRegisterInfo.setUserId(1);
            nettyRegisterInfo.setUserType(2);
            final NettyBaseFeed<Netty_RegisterInfo> reqRegisterVONettyBaseFeed = new NettyBaseFeed<>();
            reqRegisterVONettyBaseFeed.setCmd(1);
            reqRegisterVONettyBaseFeed.setModule(1);
            reqRegisterVONettyBaseFeed.setData(nettyRegisterInfo);
            NettyClient.getInstance().sendMessage(reqRegisterVONettyBaseFeed, null);
        }
    
        public class NetworkReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
                if (activeNetwork != null) { // connected to the internet
                    if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI
                            || activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
                        connect();
                        Log.e(TAG, "connecting ...");
                    }
                }
            }
        }
    
  • NettyClient类

    public class NettyClient {
    
        private static NettyClient nettyClient = new NettyClient();
    
        private EventLoopGroup group;
    
        private NettyListener listener;
    
        private Channel channel;
    
        private boolean isConnect = false;
    
        private int reconnectNum = Integer.MAX_VALUE;
    
        private long reconnectIntervalTime = 5000;
        public final static String TAG = NettyClient.class.getName();
        private final Gson gson;
        private Bootstrap bootstrap;
    
        public NettyClient() {
            gson = new Gson();
        }
    
        public static NettyClient getInstance() {
            return nettyClient;
        }
    
        public synchronized NettyClient connect() {
            if (!isConnect) {
                group = new NioEventLoopGroup();
                bootstrap = new Bootstrap().group(group)
                        .option(ChannelOption.SO_KEEPALIVE, true)
                        .option(ChannelOption.SO_BACKLOG, 128)
                        .option(ChannelOption.TCP_NODELAY, true)
                        .channel(NioSocketChannel.class)
                        .handler(new NettyClientInitializer(listener));
                try {
                    ChannelFuture future = bootstrap.connect(UrlConstant.SOCKET_HOST, UrlConstant.SOCKET_PORT).sync();
                    if (future != null && future.isSuccess()) {
                        channel = future.channel();
                        isConnect = true;
                    } else {
                        isConnect = false;
                    }
    
    
                } catch (Exception e) {
                    e.printStackTrace();
                    listener.onServiceStatusConnectChanged(NettyListener.STATUS_CONNECT_ERROR);
                    reconnect();
                }
            }
            return this;
        }
    
        public void disconnect() {
            group.shutdownGracefully();
        }
    
        public void reconnect() {
            if (reconnectNum > 0 && !isConnect) {
                reconnectNum--;
                try {
                    Thread.sleep(reconnectIntervalTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                disconnect();
                connect();
            } else {
                disconnect();
            }
        }
    
        public Channel getChannel() {
            return channel;
        }
    
        /**
         * 发送消息
         *
         * @param vo  发送消息的Json对象
         * @param futureListener 发送成功与否的监听
         */
        public void sendMessage(NettyBaseFeed vo, FutureListener futureListener) {
            boolean flag = channel != null && isConnect;
            if (!flag) {
                Log.e(TAG, "------尚未连接");
                return;
            }
            final String s = gson.toJson(vo);
            if (futureListener == null) {
                channel.writeAndFlush(s).addListener(new FutureListener() {
    
                    @Override
                    public void success() {
                        Log.e(TAG, "发送成功--->" + s);
                    }
    
                    @Override
                    public void error() {
                        Log.e(TAG, "发送失败--->" + s);
                    }
                });
            } else {
                channel.writeAndFlush(s).addListener(futureListener);
            }
        }
    
        /**
         * 设置重连次数
         *
         * @param reconnectNum 重连次数
         */
        public void setReconnectNum(int reconnectNum) {
            this.reconnectNum = reconnectNum;
        }
    
        /**
         * 设置重连时间间隔
         *
         * @param reconnectIntervalTime 时间间隔
         */
        public void setReconnectIntervalTime(long reconnectIntervalTime) {
            this.reconnectIntervalTime = reconnectIntervalTime;
        }
    
        public boolean getConnectStatus() {
            return isConnect;
        }
    
        /**
         * 设置连接状态
         *
         * @param status
         */
        public void setConnectStatus(boolean status) {
            this.isConnect = status;
        }
    
        public void setListener(NettyListener listener) {
            if (listener == null) {
                throw new IllegalArgumentException("listener == null ");
            }
            this.listener = listener;
        }
    
    
    }
    
然后发送认证数据至服务器
  • 接收服务器的消息 从NettyClientHandler的回调方法channelRead0 这里开始 调用至service之后再遍历NettyActivity的子类 通过主线程的Handler 分发至主线程

    public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
        private static final String TAG = NettyClientHandler.class.getName();
        private NettyListener listener;
    
        public NettyClientHandler(NettyListener listener) {
            this.listener = listener;
        }
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            NettyClient.getInstance().setConnectStatus(true);
            listener.onServiceStatusConnectChanged(NettyListener.STATUS_CONNECT_SUCCESS);
        }
    
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            NettyClient.getInstance().setConnectStatus(false);
            listener.onServiceStatusConnectChanged(NettyListener.STATUS_CONNECT_CLOSED);
            NettyClient.getInstance().reconnect();
        }
    
        @Override
        protected void channelRead0(ChannelHandlerContext channelHandlerContext, String byteBuf) throws Exception {
            Log.e(TAG, "thread == " + Thread.currentThread().getName());
            Log.e(TAG, "来自服务器的消息 ====》" + byteBuf);
            listener.onMessageResponse(byteBuf);
    
        }
    
  • 主线程发送消息

     NettyClient.getInstance().sendMessage(baseFeed, null);
    
  • 注意 解码器和编码器 要与服务器保持一致
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36296142/article/details/79387662

智能推荐

关于win7 下面 jlink 固件 修复-程序员宅基地

文章浏览阅读155次。从keil4过渡到MDK5后,遇到的第一个问题就是下载时MDK提示需要将keil的固件升级,一想环境不一样,估计估计需要升级一下,于是手残点了升级,于是就悲剧了,项目中断,倒腾固件修复倒腾了一天,下面说下遇到的问题。固件修复后,jlink上灯就不亮了,不亮就不亮,固件升级原来也做过,不难,可是好像忘了一个问题,原来的开发环境在winxp下,后来换成了win7 64位,就是这个环境让我..._win7 sp1补丁包和jlink

Task 4 基于深度学习的文本分类1_基于tf的文本分类-程序员宅基地

文章浏览阅读185次。Task 4 基于深度学习的文本分类1与传统机器学习不同,深度学习即提供特征提取功能,也可以完成分类的功能。4.1 学习目标1.学习FastText的使用和基础原理2.学会使用验证集进行调参4.2 现有文本表示方法的缺陷上一章节介绍了几种文本表示方法:1.One-hot2.Bag of Words3.N-gram4.TF-IDF上述方法或多或少都存在一定的问题:转换得到的向量维度很高,需要较长的训练时间;没有考虑单词与单词之间的关系,只是进行了统计。与上述方法不同,深度学习也可以用于_基于tf的文本分类

session一些基本的东西_session rolling-程序员宅基地

文章浏览阅读160次。sessionsession是什么session是因为cookie的弊端(存放在客户端,容易被客户修改伪造,数据量大也有纯传输问题) 才被做出来的,用session存储在服务器中,这让他的安全性也相对高一点session是一次浏览器和服务器的交互的会话,session也是一种存储方案服务器建立一个session,会在客户端建立一个唯一的识别(目的是为了只有这个客户端才能获得这个sessionsession的标识也会根据浏览器有关系 不同的浏览器的同一用户是不同的标识session 的运作通过_session rolling

Duilib的简单使用(四、换肤)_dulib皮肤-程序员宅基地

文章浏览阅读1.4k次。一、前言在Duilib的简单使用(一、duilib demo)中我们介绍了利用duilib简单的构造一个项目在Duilib的简单使用(二、xml实现界面与业务分离)中我们介绍了XML在duilib中的使用在Duilib的简单使用(三、界面逻辑交互)中我们已经知道如何简单的进行界面的交互这一篇,我们来提一下,Duilib强大的一键换肤功能。二、函数介绍Duilib是一个以贴图为主要表现手段的界面库,实现换肤非常简单,可以通过给控件设置不同的图片来实现换肤,比如给需要换肤的控件调用CControlU_dulib皮肤

SpringMVC常见面试题总结_springmvc面试-程序员宅基地

文章浏览阅读2.1w次,点赞37次,收藏340次。SpringMVC常见面试题总结1. 什么是SpringMVC?SpringMVC是一种基于 Java 的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于Spring框架的一个模块。它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful编程风格的请求。2.什么是MVC模式?MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范。它是_springmvc面试

matplotlib 通过for循环画多张图-程序员宅基地

文章浏览阅读1.2w次,点赞7次,收藏16次。思路利用plt.clf()在每次画完图片后,更新画布。代码#导入两个包import matplotlib.pyplot as pltimport numpy as np #数据准备x = np.arange(27)x = np.reshape(x, (3,9)) #建立for循环语句,绘制x的前三列for i in range(3): plt.plot(x[:,i]) # plt.show() #保存图片的时候不要plt.show() plt.savefig

随便推点

前端传参数,java后端接收为null_前端传参,java接收为null-程序员宅基地

文章浏览阅读1.6w次,点赞6次,收藏8次。开发接口时,出现个离奇问题。在对接第三方接口时,按对方接口参数进行传参,却一直接收不到,为null值,检查所有代码,并不是代码问题。我将代码整理并创建简单接口进行测试,如图:测试实体类测试实现类postman测试参数debug接收参数为null在测试时,无论如何参数都为接收都为null,在折腾许久,终于发现时实体类里的@Data注解的原因一下是我截取出的get/set方法;最终原因就是出在参数名命名不规范,造成@Data注解在生产class文件时出现问题。造成所生成的get/set方_前端传参,java接收为null

小米6能读取卡信息无服务器,MIUI官方回应:米6公交开卡系服务升级、NFC功能可正常使用...-程序员宅基地

文章浏览阅读592次。原标题:MIUI官方回应:米6公交开卡系服务升级、NFC功能可正常使用近日,有消息称小米6因为系统升级暂时关闭了NFC公交开卡服务,或涉及虚假宣传。对此,小米官方也给予了回应,以下为小米MIUI官方在论坛上的回应:NFC(近场通信)功能拥有三种工作模式:读卡器模式(Reader/Writer mode)、点对点模式(P2P mode)、卡模拟模式(Card emulation mode)。读卡器模..._小米6读卡器

报错The code generator has deoptimised the styling of ...as it exceeds the max of 500KB.-程序员宅基地

文章浏览阅读3.1w次,点赞4次,收藏3次。先贴出报错:字面意思是:babel警告,代码生成器已经将这块js去除了styling, 因为他超过了500KB.解决方案:{ test: /.js$/, exclude: /node_modules/, use: 'babel-loader'},..._the code generator has deoptimised the styling of undefined as it exceeds th

MEMZ木马病毒-程序员宅基地

文章浏览阅读1.3w次,点赞3次,收藏32次。今天做蠕虫弄个memz病毒,把虚拟机搞崩了,重装了一下才解决,详细的了解了一下这种病毒。MEMZ病毒:MEMZ病毒又称彩虹猫病毒,在运行时,该病毒会不断弹窗导致系统无法正常运行,如果尝试结束MEMZ进程或重启系统,桌面会弹出无数个包含“火星文”的消息对话框,随后计算机进入蓝屏状态。重启后,会在屏幕顶部出现一段英文(译文:你的电脑已经被MEMZ病毒损坏,现在一起来欣赏彩虹猫吧),最后出现一个跳跃的“彩虹猫”动画。运行环境:虚拟机!!!!源代码:Github上有源码,不过好像是越南语的注释,不太_memz

python lxml中etree的简单应用3_datas =etree.html(data)-程序员宅基地

文章浏览阅读551次。本次主要介绍,无论使用的xpath表达式中是否包含text()方法,最后都可以获取目标标签下的文本。使用的依然是etree.HTML和etree.tostring方法。1.思路首先将字符串源码转换成_Element对象,然后使用_Element对象的xpath()方法解析xpath表达式。如果通过xpath表达式解析得到的是文本对象,那么先将文本对象(也是字符串)转换成_Element对象,最后通过etree.tostring方法获取_Element对象中的文本内容(可以参考这里)。2.代码实现_datas =etree.html(data)

【大语言模型LLM】- AI工具收录集合,一篇就够了!-程序员宅基地

文章浏览阅读728次,点赞13次,收藏19次。大语言模型乐园,国内外大模型集合,持续更新...

推荐文章

热门文章

相关标签