Android产品研发(十二)-->App长链接实现

 

而本文中咱们将讲解一下App的长链接实现。通常而言长链接已是App的标配了,推送功能的实现基础就是长链接,固然了咱们也能够经过轮训操做实现推送功能,可是轮训通常及时性比较差,并且网络消耗与电量销毁比较多,所以通常推送功能都是经过长链接实现的。java

那么如何实现长链接呢?如今通常有这么几种实现方式:服务器

  • 使用第三方的长链接服务;网络

  • 经过NIO等方案实现长链接服务;session

  • 经过MINA等第三方框架实现长链接;框架

几种长链接服务的具体实现,以及各自的优缺点。

1. 使用第三方的长链接服务

介绍:这是最简单的方式,咱们能够经过接入极光推送,百度推送,友盟等第三方服务实现长链接,经过接入第三方的API咱们能够很方便的接入第三方的长链接,推送服务,可是这种方式定制化程度不太好,若是对长链接服务不是要求特别高,对定制化要求不是很高的话基本能够考虑这种方式(目前主流的App都是使用第三方的长链接服务) 
优点:简单,方便 
劣势:定制化程度不高ide

2. 使用NIO等方案实现长链接服务

介绍:经过NIO的方式实现长链接,这种方式对技术要求程度比较高,基本都是经过java API实现长链接,实现心跳包,实现异常状况的容错等操做,能够说经过NIO实现长链接对技术要求很高,通常若是没有成行的技术方案比建议这么作,就算实现了长链接,后期链接的维护,对电量,流量的损耗等都须要持续的优化。 
优点:定制化比较高 
劣势:技术要求高,须要持续的维护oop

3. 使用MINA等第三方框架实现长链接

介绍:MINA是一个第三方的NIO框架,该框架实现了一整套的长链接机制,包括长链接的创建,心跳包的实现,异常机制的容错等。使用MINA实现长链接能够定制化的实现一些特有的功能,而且比NIO方案较为简单,由于其已经封装了一些长链接的特有机制,好比心跳包,容错等。 
优点:可定制,较NIO方法简单 
劣势:也须要必定的技术储备优化

长链接具体实现

在咱们的Android客户端中长链接的实现机制采用–MINA方式。这里多说一句,一开始的长链接采用的是NIO方案,可是采用这种方案以后踩了不少坑,包括心跳,容错等机制都是本身写的,因此耗费了大量的时间,并且对手机电量的消耗很大,最后决定使用MINA NIO框架从新实现一遍长链接,后来通过实测,长链接的稳定性还有耗电量,流量的消耗等指标方面有了很大的提升。ui

下面我将简单的介绍一下经过NIO实现长链接的具体流程:this

  • 引入MINA jar包,在App启动页面,登陆页面启动长链接;

  • 建立后台服务,在服务中建立MINA长链接;

  • 实现心跳包,重写一些容错机制;

  • 实现长链接断了以后的重连机制,而且重连次数有限制不能一直重连;

  • 长链接断了以后实现轮训操做,这里的轮训服务只有在长链接断了以后才启动,在长链接恢复以后关闭;

如下就是在长链接中实现的具体代码:

  • 在Application的onCreate方法中检测App是否登陆,若登陆的话启动长链接
/**
 * 在Application的onCreate方法中执行启动长链接的操做
 **/
@Override
    public void onCreate() {
        ... // 登陆后开启长链接 if (UserConfig.isPassLogined()) { L.i("用户已登陆,开启长链接..."); startLongConn(); } ... }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 经过闹钟服务实现具体的启动长链接service的操做,即每隔60秒钟判断长链接是否启动,若未启动则实现启动操做
/** * 开始执行启动长链接服务 */ public void startLongConn() { quitLongConn(); L.i("长链接服务已开启"); AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(this, LongConnService.class); intent.setAction(LongConnService.ACTION); PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); long triggerAtTime = SystemClock.elapsedRealtime(); manager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime, 60 * 1000, pendingIntent); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 下面的代码就是长链接服务的具体实现
/** * 后台长链接服务 **/ public class LongConnService extends Service { public static String ACTION = "com.youyou.uuelectric.renter.Service.LongConnService"; private static MinaLongConnectManager minaLongConnectManager; public String tag = "LongConnService"; private Context context; @Override public int onStartCommand(Intent intent, int flags, int startId) { context = getApplicationContext(); // 执行启动长链接的操做 startLongConnect(); ObserverManager.addObserver("LongConnService", stopListener); return START_STICKY; } public ObserverListener stopListener = new ObserverListener() { @Override public void observer(String from, Object obj) { closeConnect(); } }; @Override public void onDestroy() { super.onDestroy(); closeConnect(); } /** * 开始执行启动长链接的操做 */ private void startLongConnect() { if (Config.isNetworkConnected(context)) { if (minaLongConnectManager != null && minaLongConnectManager.checkConnectStatus()) { L.i("长链接状态正常..."); return; } if (minaLongConnectManager == null) { startThreadCreateConnect(); } else { if (minaLongConnectManager.connectIsNull() && minaLongConnectManager.isNeedRestart()) { L.i("session已关闭,须要从新建立一个session"); minaLongConnectManager.startConnect(); } else { L.i("长链接已关闭,须要重开一个线程来从新建立长链接"); startThreadCreateConnect(); } } } } private final AtomicInteger mCount = new AtomicInteger(1); private void startThreadCreateConnect() { if (UserConfig.getUserInfo().getB3Key() != null && UserConfig.getUserInfo().getSessionKey() != null) { System.gc(); new Thread(new Runnable() { @Override public void run() { // 执行具体启动长链接操做 minaLongConnectManager = MinaLongConnectManager.getInstance(context); minaLongConnectManager.crateLongConnect(); } }, "longConnectThread" + mCount.getAndIncrement()).start(); } } private void closeConnect() { if (minaLongConnectManager != null) { minaLongConnectManager.closeConnect(); } minaLongConnectManager = null; // 中止长链接服务LongConnService stopSelf(); } @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 而下面的代码就是长链接的具体实现操做,具体的代码有相关注释说明
/** * 具体实现长链接的管理对象 **/ public class MinaLongConnectManager { private static final String TAG = MinaLongConnectManager.class.getSimpleName(); /** * 服务器端口号 */ public static final int DEFAULT_PORT = 18156; /** * 链接超时时间,30 seconds */ public static final long SOCKET_CONNECT_TIMEOUT = 30 * 1000L; /** * 长链接心跳包发送频率,60s */ public static final int KEEP_ALIVE_TIME_INTERVAL = 60; private static Context context; private static MinaLongConnectManager minaLongConnectManager; private static NioSocketConnector connector; private static ConnectFuture connectFuture; public static IoSession session; private static ExecutorService executorService = Executors.newSingleThreadExecutor(); /** * 长链接是否正在链接中... */ private static boolean isConnecting = false; private MinaLongConnectManager() { EventBus.getDefault().register(this); } public static synchronized MinaLongConnectManager getInstance(Context ctx) { if (minaLongConnectManager == null) { context = ctx; minaLongConnectManager = new MinaLongConnectManager(); } return minaLongConnectManager; } /** * 检查长链接的各类对象状态是否正常,正常状况下无需再建立 * * @return */ public boolean checkConnectStatus() { if (connector != null && connector.isActive() && connectFuture != null && connectFuture.isConnected() && session != null && session.isConnected()) { return true; } else { return false; } } public boolean connectIsNull() { return connector != null; } /** * 建立长链接,配置过滤器链和心跳工厂 */ public synchronized void crateLongConnect() { // 若是是长链接正在建立中 if (isConnecting) { L.i("长链接正在建立中..."); return; } if (!Config.isNetworkConnected(context)) { L.i("检测到网络未打开,没法正常启动长链接,直接return..."); return; } // 检查长链接的各类对象状态是否正常,正常状况下无需再建立 if (checkConnectStatus()) { return; } isConnecting = true; try { connector = new NioSocketConnector(); connector.setConnectTimeoutMillis(SOCKET_CONNECT_TIMEOUT); if (L.isDebug) { if (!connector.getFilterChain().contains("logger")) { // 设置日志输出工厂 connector.getFilterChain().addLast("logger", new LoggingFilter()); } } if (!connector.getFilterChain().contains("codec")) { // 设置请求和响应对象的编解码操做 connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new LongConnectProtocolFactory())); } // 建立心跳工厂 ClientKeepAliveMessageFactory heartBeatFactory = new ClientKeepAliveMessageFactory(); // 当读操做空闲时发送心跳 KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory, IdleStatus.READER_IDLE); // 设置是否将事件继续往下传递 heartBeat.setForwardEvent(true); // 设置心跳包请求后超时无反馈状况下的处理机制,默认为关闭链接,在此处设置为输出日志提醒 heartBeat.setRequestTimeoutHandler(KeepAliveRequestTimeoutHandler.LOG); //设置心跳频率 heartBeat.setRequestInterval(KEEP_ALIVE_TIME_INTERVAL); if (!connector.getFilterChain().contains("keepAlive")) { connector.getFilterChain().addLast("keepAlive", heartBeat); } if (!connector.getFilterChain().contains("reconnect")) { // 设置长链接重连过滤器,当检测到Session(会话)断开后,重连长链接 connector.getFilterChain().addLast("reconnect", new LongConnectReconnectionFilter()); } // 设置接收和发送缓冲区大小 connector.getSessionConfig().setReceiveBufferSize(1024); connector.getSessionConfig().setSendBufferSize(1024); // 设置读取空闲时间:单位为s connector.getSessionConfig().setReaderIdleTime(60); // 设置长链接业务逻辑处理类Handler LongConnectHandler longConnectHandler = new LongConnectHandler(this, context); connector.setHandler(longConnectHandler); } catch (Exception e) { e.printStackTrace(); closeConnect(); } startConnect(); } /** * 开始或重连长链接 */ public synchronized void startConnect() { if (connector != null) { L.i("开始建立长链接..."); boolean isSuccess = beginConnect(); // 建立成功后,修改建立中状态 if (isSuccess) { isNeedRestart = false; if (context != null) { // 长链接启动成功后,主动拉取一次消息 LoopRequest.getInstance(context).sendLoopRequest(); } } else { // 启动轮询服务 startLoopService(); } isConnecting = false; // printProcessorExecutor(); } else { L.i("connector已为null,不能执行建立链接动做..."); } } /** * 检测MINA中线程池的活动状态 */ private void printProcessorExecutor() { Class connectorClass = connector.getClass().getSuperclass(); try { L.i("connectorClass:" + connectorClass.getCanonicalName()); Field field = connectorClass.getDeclaredField("processor"); field.setAccessible(true); Object connectorObject = field.get(connector); if (connectorObject != null) { SimpleIoProcessorPool processorPool = (SimpleIoProcessorPool) connectorObject; Class processPoolClass = processorPool.getClass(); Field executorField = processPoolClass.getDeclaredField("executor"); executorField.setAccessible(true); Object executorObject = executorField.get(processorPool); if (executorObject != null) { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorObject; L.i("线程池中当前线程数:" + threadPoolExecutor.getPoolSize() + "\t 核心线程数:" + threadPoolExecutor.getCorePoolSize() + "\t 最大线程数:" + threadPoolExecutor.getMaximumPoolSize()); } } else { L.i("connectorObject = null"); } } catch (Exception e) { e.printStackTrace(); } } /** * 开始建立Session * * @return */ public boolean beginConnect() { if (session != null) { session.close(false); session = null; } if (connectFuture != null && connectFuture.isConnected()) { connectFuture.cancel(); connectFuture = null; } FutureTask<Boolean> futureTask = new FutureTask<>(new Callable<Boolean>() { @Override public Boolean call() { try { InetSocketAddress address = new InetSocketAddress(NetworkTask.getBASEURL(), DEFAULT_PORT); connectFuture = connector.connect(address); connectFuture.awaitUninterruptibly(3000L); session = connectFuture.getSession(); if (session == null) { L.i(TAG + "链接建立失败...当前环境:" + NetworkTask.getBASEURL()); return false; } else { L.i(TAG + "长链接已启动,链接已成功...当前环境:" + NetworkTask.getBASEURL()); return true; } } catch (Exception e) { return false; } } }); executorService.submit(futureTask); try { return futureTask.get(); } catch (Exception e) { return false; } } /** * 关闭链接,根据传入的参数设置session是否须要从新链接 */ public synchronized void closeConnect() { if (session != null) { session.close(false); session = null; } if (connectFuture != null && connectFuture.isConnected()) { connectFuture.cancel(); connectFuture = null; } if (connector != null && !connector.isDisposed()) { // 清空里面注册的因此过滤器 connector.getFilterChain().clear(); connector.dispose(); connector = null; } isConnecting = false; L.i("长链接已关闭..."); } private volatile boolean isNeedRestart = false; public boolean isNeedRestart() { return isNeedRestart; } public void onEventMainThread(BaseEvent event) { if (event == null || TextUtils.isEmpty(event.getType())) return; if (EventBusConstant.EVENT_TYPE_NETWORK_STATUS.equals(event.getType())) { String status = (String) event.getExtraData(); // 当网络状态变化的时候请求startQuery接口 if (status != null && status.equals("open")) { if (isNeedRestart && UserConfig.getUserInfo().getB3Key() != null && UserConfig.getUserInfo().getSessionKey() != null) { L.i("检测到网络已打开且长链接处于关闭状态,须要启动长链接..."); Intent intent = new Intent(context, LongConnService.class); intent.setAction(LongConnService.ACTION); context.startService(intent); } } } } /** * 出现异常、session关闭后,接收事件进行长链接重连操做 */ public void onEventMainThread(LongConnectMessageEvent event) { if (event.getType() == LongConnectMessageEvent.TYPE_RESTART) { long currentTime = System.currentTimeMillis(); // 票据有效的状况下进行重连长链接操做 if (UserConfig.getUserInfo().getB3Key() != null && UserConfig.getUserInfo().getSessionKey() != null && ((currentTime / 1000) < UserConfig.getUserInfo().getUnvalidSecs())) { // 等待2s后从新建立长链接 SystemClock.sleep(1000); if (Config.isNetworkConnected(context)) { L.i("出现异常状况,须要自动重连长链接..."); startConnect(); } else { isNeedRestart = true; L.i("长链接出现异常,须要从新建立session会话..."); } } } else if (event.getType() == LongConnectMessageEvent.TYPE_CLOSE) { L.i("收到session屡次close的消息,此时须要关闭长链接,等待下次闹钟服务来启动..."); closeConnect(); } } /** * 启动轮询服务 */ public void startLoopService() { // 启动轮询服务 // 暂时不考虑加入网络状况的判断... if (!LoopService.isServiceRuning) { // 用户是登陆态,启动轮询服务 if (UserConfig.isPassLogined()) { // 判断当前长链接的状态,若长链接已链接,则再也不开启轮询服务 if (MinaLongConnectManager.session != null && MinaLongConnectManager.session.isConnected()) { LoopService.quitLoopService(context); return; } LoopService.startLoopService(context); } else { LoopService.quitLoopService(context); } } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325

以上是经过NIO实现App长链接的部分核心代码,NIO中其实已经实现了长链接的核心流程,咱们须要作的就是按照其流程实现长链接,须要注意的是要处理好异常状况,重连机制等。

当长链接建立成功以后须要从新拉取一次服务器端的长链接消息,而且这里的长链接作了容错处理,当长链接断了以后须要有重连机制,一直启动轮训服务,当长链接修复以后轮训服务退出。以上只是经过MINA框架实现的长链接操做的核心流程,还有一些长链接实现的操做细节这里就不作过多的说明。

总结: 
基本上对于App来讲长链接已是标配了,产品开发人员能够根据具体的产品需求选择不一样的实现方式,通常而言使用第三方的推送服务已经能够知足大部分的需求了,固然了如果相对技术有所追求的话也能够选择本身实现一套长链接服务,不过其中可能存在一些坑须要填,但愿这里的长链接实现可以对你们对长链接实现上有所帮助。

    • 能够经过使用第三方长链接服务或者是本身实现链接的方式;

    • 自定义实现长链接能够经过使用NIO或者是第三方NIO框架,好比MINA实现;

    • 长链接实现中经过心跳包的机制实现App与服务器的长时间链接;

    • 能够经过闹钟的机制定时检测长链接服务是否可靠,长链接是否出现异常等;

    • 为了消息的及时性,在长链接出现异常状况时可经过建立轮训服务的机制实现对消息的获取,待长链接恢复以后关闭轮训服务;

相关文章
相关标签/搜索