评论

小程序保持长连接小经验

小程序websocket长连技术

大家都知道,小程序的websocket在切入后台5秒左右,会断开链接,或者长时间无数据收发,也会切断链接。
然而心跳数据并不能完全保证链接的正常,
我在这里说一下我的经验,我初中毕业(真的),代码方面写的不好不要见笑。
首先,我为了知道当前的网络是否断了,使用了一个标志位比如 :
var NetworkIsOK = false;
当首次链接打开时比如socket的 onOpen 事件!在这个事件回调中,将NetworkIsOK = true;
同理,如果网络出现错误,在错误的回调中将NetworkIsOK = false;
建立一个发送 发送区数据 暂存站
var SendBuffer =[];
将socket的send 函数包装一下,比如取名SendToServer(data)
在SendToServer中,首先检查网络的状态,如果状态是正常的,则直接调用socket.send()发送数据,
如果不是正常的,则重新链接服务器,并在onOpen事件中检查 SendBuffer.length是否大于 0 ,如果有存入的缓冲数据,则依次发送掉, 以下是部分实际代码,请忽略我垃圾的编程水平!

var app = getApp();
/**
 * 与服务器进行通信的所有操作在此进行
 */
var Server = {};
Server.socket = null; //socket连接句柄
Server.isOK = false//服务器连接状态处理数组
Server.event = []; //事件注册处理数组
Server.url = 'wss://********'; //服务器地址
Server.SendBuffer=[]; //数据包发送缓冲
/**
 * 初始化操作
 */
Server.Init=function(apps){
  console.log('hello server');
   app = apps;
  console.log(app);
  var Timer;
  /**执行服务器连接逻辑 */
    Server.socket = wx.connectSocket({
      url:Server.url
    });
    //132.232.87.229
    Server.socket.onOpen(function () {
      console.log('Server open');
      Server.isOK=true; //可以通信了
      //显示成功
      wx.showToast({
        title: '已连接服务器 ',
      });
      Timer = setInterval(function () {
        Server.startHeart();
      }, 1000 * 50);
    });
    Server.socket.onError(function () {
      console.log('Server error');
      Server.isOK = false;
      //显示成功
      wx.showToast({
        title: '服务器连接错误',
        icon:'none'
      });
      //Server.reLink();
      clearInterval(Timer);
    });
    Server.socket.onClose(function () {
      console.log('Server close');
      Server.isOK = false;
      //显示成功
      wx.showToast({
        title: '服务器连接关闭',
        icon: 'none'
      });
      //Server.reLink();
      clearInterval(Timer);
    });
    Server.socket.onMessage(function (res) {
      //Server.socketPress.onMessage(res);
      var message = JSON.parse(res.data);
      if(!message)  return; //空数据
      var Operator = message.Operator;
      var event=Server.event[Operator];
      if(event){
        event(message);  //实际执行
      }
    });

} /**服务器重连**/

Server.reLink=function(){
  var Timer;
  /**执行服务器连接逻辑 */
  Server.socket = wx.connectSocket({
    url:Server.url
  });
  //132.232.87.229
  Server.socket.onOpen(function () {
    console.log('Server open');
    Server.isOK = true; //可以通信了
    //显示成功
    wx.showToast({
      title: '已连接服务器 ',
    });
    Server.Login();//重新注册登入
    Timer = setInterval(function(){
      Server.startHeart();
    },1000*50);
    //检查缓冲区是否有未发送数据
    while (Server.SendBuffer.length>0){
      var data = Server.SendBuffer.pop();
      //将用户的code发往服务器
      Server.socket.send({
        data: data
      });
      console.log('将缓存中的信息发送',data)
    }
  });
  Server.socket.onError(function () {
    console.log('Server error');
    Server.isOK = false;
    //显示成功
    wx.showToast({
      title: '服务器连接错误',
      icon: 'none'
    });
    //Server.reLink();
    clearInterval(Timer);
  });
  Server.socket.onClose(function () {
    console.log('Server close');
    Server.isOK = false;
    //显示成功
    wx.showToast({
      title: '服务器连接关闭',
      icon: 'none'
    });
    //Server.reLink();
    clearInterval(Timer);
  });
  Server.socket.onMessage(function (res) {
    //Server.socketPress.onMessage(res);
    var message = JSON.parse(res.data);
    if (!message) return; //空数据
    var Operator = message.Operator;
    var event = Server.event[Operator];
    if (event) {
      event(message);  //实际执行
    }
  });
};
/**
 * 启动心跳
 */
Server.startHeart=function(){
  if (Server.isOK == false) {
    Server.reLink(); //重连
    return;
  }
  var sendData = {
    Operator: 'Heart', //操作方式
  };
  var JsonData = JSON.stringify(sendData);
  // console.log(JsonData);
  //将用户的code发往服务器
  Server.socket.send({
    data: JsonData
  });
  Server.addEvent('HeartOK',function(message){
   // console.log('心跳OK',message);
  })
}
/**用户登陆 */
Server.Login=function(ques){
  var userOpenId = wx.getStorageSync('openId');
  console.log(app);
  var sendData = {
    Operator: 'userLogin', //操作方式
    userCode: app.userCode,     //用户code
    userInfo: app.userInfo,  //用户信息
  };
  if (userOpenId) {  //如果缓存中的有效,就用缓存中的openId发过去给服务器
    sendData.userOpenId = userOpenId;
    console.log('调用缓存openID');
  }
 
  var JsonData = JSON.stringify(sendData);
  console.log("登陆数据:", JsonData);
  // console.log(JsonData);
  //将用户的code发往服务器
  Server.SendData(sendData);
  /**如果是黑名单用户,禁止使用 */
  Server.addEvent('BanLogin',function(message){
    if (ques) {
      ques();
    }
  });
};
/**
 * 注册消息执行处理函数
 */
Server.addEvent=function(eventName,eventHandle){
   Server.event[eventName] = eventHandle;
}
/**注册登入成功处理事件 */
Server.addEvent('LoginOK',function(message){
  console.log('LOGIN OK');
  console.log(message);
  wx.setStorageSync('openId',message.openId);
});
/**注册登入失败处理事件 */
Server.addEvent('LoginError', function (message) {
  wx.showModal({
    content: '登入失败了!部分功能可能无法使用,可能是网络原因,也可能是没有获得授权',
    showCancel: false,
    success: function (res) {
      if (res.confirm) {
        //console.log('用户点确定');
      }
    }
  });
});
/**
 * 创建帖子
 */
Server.CreateInvitation=function(table,image,text,isRichText){
  var sendData = {
    Operator: 'CreateInvitation', //操作方式
    isRichText:isRichText,//是否为富文本
    Table:table,//标题
    Image:image,//图片地址
    Text:text,//文本内容
  };
  Server.SendData(sendData);
};
/**
 * 从服务器获取贴子
 */
Server.GetInvitation=function(id,mode,time,limt,skip,success){
  var sendData = {
    Operator: 'GetInvitation', //操作方式
    id:id, //使用帖子ID的查询方式
    mode:mode, //操作模式
    time:time, //时间查询时使用的时间
    limt:limt, //分页查询时需要获取的贴子数量
    skip:skip, //需要跳过的帖子数量
  };
  //var JsonData = JSON.stringify(sendData);
  Server.SendData(sendData);
  /**注册登入成功处理事件 */
  Server.addEvent('GetInvitationOK', function (message) {
    console.log('GetInvitationOK');
    var data = message.data;
    var serverTime=message.serverTime;
    if(success) success(data,serverTime);  //回调执行
  });
}
/**
 * 创建帖子评论
 */
Server.CreateInvitationComment=function(_id,text,success){
  var sendData = {
    Operator: 'CreateInvitationComment', //操作方式
    id:_id, //使用帖子ID的查询方式
    text:text,//评论内容
  };
  Server.SendData(sendData);
  /**注册登入成功处理事件 */
  Server.addEvent('CreateInvitationCommentOK', function (message) {
    console.log('CreateInvitationCommentOK');
    var data = message.data;
    if (success) success(data);  //回调执行
  });
};
/**
 * 给帖子点赞
 */
Server.LoveInvitation=function(_id,success){
  var sendData = {
    Operator: 'LoveInvitation', //操作方式
    id:_id, //使用帖子ID的查询方式
  };
  Server.SendData(sendData);
  /**注册登入成功处理事件 */
  Server.addEvent('LoveInvitationOK', function (message) {
    console.log('LoveInvitationOK');
    if (success) success();  //回调执行
  });
}
/**
 * 向服务器发送数据,数据类型为任意数据,
 * 如果服务器断线,则自动重连服务器,数据被暂存,重连成功后将被发送
 */
Server.SendData=function(data){
  if (Server.isOK == false) {
    Server.reLink(); //重连
    //将未发送数据存入Buffer
    var JsonData = JSON.stringify(data);
    Server.SendBuffer.push(JsonData);
    return;
  }else{ //否则直接给服务器发送数据
    var JsonData = JSON.stringify(data);
    Server.socket.send({
      data: JsonData
    });
  }
}
//暴露接口
module.exports.Server = Server;


点赞 5
收藏
评论

3 个评论

  • 小程序技术专员-villainhr
    小程序技术专员-villainhr
    2019-03-19

    这个切入点很好,不过,可以事先阐述一下你的方案是什么,已经解决的问题是啥?这样后面的读者能更好的了解你的文章目的。


    推荐下次 可以将代码 拆分为一段一段来讲,其实,分享也是一种学习方式。


    学历是社会给你的标签,不是你自己给你的标签。


    加油。

    2019-03-19
    赞同 3
    回复 1
    • KeepSmile
      KeepSmile
      2019-03-19

      嗯,我的想法很简单,就是保证数据都能被有效的发送,所以整了这么个, 就目前的使用来看效果比较好,即使断线了出错了,只要一有数据发送,就能重新连接,然后发送数据, 因为是直接复制的项目代码,所以里面还有消息的处理方式,看起来不够简单

      2019-03-19
      回复
  • 郭玉峰 15811200580
    郭玉峰 15811200580
    2019-07-10

    有没有wss域名搭建的教程啊 求分享

    2019-07-10
    赞同
    回复
  • 璀璨星空
    璀璨星空
    2019-03-19

    还行 后台也做过websocket,对长连接更加深入,代码还有很多优化的余地,es5的写法比较多,距离老司机还有点距离

    2019-03-19
    赞同
    回复 2
    • KeepSmile
      KeepSmile
      2019-03-19

      ~是吗,忘大神指教。我是刚学的javascript~

      2019-03-19
      1
      回复
    • Mr.Zhao
      Mr.Zhao
      2019-04-10回复KeepSmile

      刚学的就会这些了 厉害

      2019-04-10
      回复
登录 后发表内容