如何在服务端封装一套远程调用接口

封装一套稳定的远程调用接口,需分两个模块:连接对象模块(Client)和对象管理模块(ClientManager)。
client的属性:

name连接名字
ip对端ip
port对端port
status连接状态
intKey连接键值
socket连接socket
reConnect可选是否自动重连参数

client的接口:

Init初始化接口
Connect连接接口
Send发送数据接口
Close关闭连接接口

clientManager的属性有:(以node.js为例)
constructor(){
this.intKey = 0;
this.isStarted = false;
this.pingTimer = 1000;//心跳包间隔
this.checkTimer = 3000; //clients 检查定时器
this.unconns = new HashMap();//需要重连的连接
this.conns = new HashMap();//已经在线的连接
this.groupConns = new HashMap(); //client分组
this.msg_handler = new WsClientMsgHandler();//消息处理接口
}

分组可以通过独立的类来实现,在一个负载均衡的系统中,可以在分组中轮询发送数据,也可以广播到分组中所有的连接。

class WsClientGroup{
    constructor(){
        this.conns = [];
        this.index = 0;
    }

    AddConn(conn){
        let index = this.conns.findIndex((val)=> val.intKey === conn.intKey);
        if(index < 0){
            this.conns.push(conn);
            return true;
        } else {
            console.error("WsClientGroup.AddConn the same conn with intKey:", conn.intKey);
            return false;
        }
    }

    DeleteConn(intKey){
        let index = this.conns.findIndex((val)=> val.intKey === intKey);
        if(index >= 0){
            this.conns.splice(index, 1);
        }
    }

    Send(data){
        if(this.conns.length < 1){
            return;
        }

        if(this.index >= this.conns.length){
            this.index = 0;
        }
        this.conns[this.index].Send(data);
        ++this.index;
    }

    SendArgs(cmd, status, msg){
        if(this.conns.length < 1){
            return;
        }

        if(this.index >= this.conns.length){
            this.index = 0;
        }
        this.conns[this.index].SendArgs(cmd, status, msg);
        ++this.index;
    }

    Broadcast(data){
        for(let i = 0; i < this.conns.length; i++){
            this.conns[i].Send(data);
        }
    }

    BroadcastArgs(cmd, status, msg){
        for(let i = 0; i < this.conns.length; i++){
            this.conns[i].SendArgs(cmd, status, msg);
        }
    }
};

clientManager的功能:
1.连接管理。
2.分组管理。
3.心跳包检测。
4.重连机制。
5.消息回调接口。
6.消息广播。
7.消息单独发送。
8.连接的开启和关闭。
9.错误信息处理。

具体实现代码如下:

class WsClientManager
{
    constructor(){
        this.intKey    = 0;
        this.isStarted = false;

        this.pingTimer  = 10000;
        this.checkTimer = 3000;
        
        this.unconns    = new HashMap();
        this.conns      = new HashMap();
        this.groupConns = new HashMap();

        this.msg_handler  = new WsClientMsgHandler();
    }

    GetIntKey(){
        ++this.intKey;
        return this.intKey;
    }

    SetMsgHandler(handler){
        this.msg_handler = handler;
        if(this.msg_handler.Init){
            this.msg_handler.Init();
        } else {
            console.error("WsClientManager.msg_handler.Init is null");
            return;
        }
        if(this.msg_handler.OnMessage == null){
            console.error("WsClientManager.msg_handler.OnMessage is null");
            return;
        }

        if(this.msg_handler.OnClose == null){
            console.error("WsClientManager.msg_handler.OnClose is null");
            return;
        }
    }

    OnUnConnected(client){
        let temp = this.unconns.get(client.intKey);
        if(null == temp){
            this.unconns.set(client.intKey, client);
        }
    }

    DeleteUnConnected(intKey){
        let temp = this.unconns.get(intKey);
        if(temp){
            this.unconns.delete(intKey);
        }
    }
    
    OnConnected(client){
        //console.log("WsClientManager OnConnected intKey:", client.intKey);

        let temp = this.unconns.get(client.intKey);
        if(temp){
            this.unconns.delete(client.intKey);
        }

        let conn = this.conns.get(client.intKey);
        if(conn){
            this.DeleteUnConnected(client.intKey);
            console.error("WsClientManager.OnConnected client exist in conns intKey:", client.intKey);
            return;
        }
        this.conns.set(client.intKey, client);

        let group = this.groupConns.get(client.name);
        if(group){
            group.AddConn(client);
        } else {
            group = new WsClientGroup();
            group.AddConn(client);
            this.groupConns.set(client.name, group);
        }

        if(this.msg_handler.OnConnected){
            this.msg_handler.OnConnected(this, client, "on_connected", "on_connected");
        }
        this.DeleteUnConnected(client.intKey);
    }

    OnMessage(client, msg) {
        let conn = this.conns.get(client.intKey);
        if(!conn){
            console.error("WsClientManager.OnMessage no conn intKey:%s, msg:%s", client.intKey, data);
            return;
        }
        
        let jsonObj = null;
        try{
            jsonObj = JSON.parse(msg);
        }catch(e){
            console.error("WsClientManager.OnMessage JSON.parse err msg:" + msg);
            return;
        }

        if(null != jsonObj && null != jsonObj.cmd && null != jsonObj.data){
            this.msg_handler.OnMessage(this, client, jsonObj.cmd, jsonObj.data);
        } else {
            console.error("WsClientManager.OnMessage jsonObj err msg:" + msg);
        }
    }

    OnClosed(client, code, reason) { 
        let conn = this.conns.get(client.intKey);
        if(!conn){
            console.error("WsClientManager.OnClosed no client in conns intKey:", client.intKey);
            return;
        }

        if(client.reConnect && code != 12345){
            this.unconns.set(client.intKey, client);
        }

        let args = {
            name:client.name,
            intKey:client.intKey
        }

        let group = this.groupConns.get(client.name);
        if(group){
            group.DeleteConn(client.intKey);
        }
        this.conns.delete(client.intKey);

        this.msg_handler.OnClose(this, client, "on_close", args);
    }

    OnError(client, code, reason) { 
        //console.error("WsClientManager.OnError code:", code, " reason:", reason, " intKey:", client.intKey);
        let conn = this.conns.get(client.intKey);
        if(conn && null != this.msg_handler.OnError){
            this.msg_handler.OnError(this, client, "on_error", "on_error");
        }
    }

    Send(intKey, msg){
        let conn = this.conns.get(intKey);
        if(conn){
            conn.Send(msg);
        }
    }

    SendArgs(intKey, cmd, status, msg){
        let conn = this.conns.get(intKey);
        if(conn){
            conn.SendArgs(cmd, status, msg);
        }
    }

    SendInRound(groupName, msg){
        let group = this.groupConns.get(groupName);
        if(group){
            group.Send(msg);
        }
    }

    SendInRoundArgs(groupName, cmd, status, msg){
        let group = this.groupConns.get(groupName);
        if(group){
            group.SendArgs(cmd, status, msg);
        }
    }

    BroadcastGroup(groupName, data){
        let group = this.groupConns.get(groupName);
        if(group){
            group.Broadcast(data);
        }
    }

    BroadcastGroupArgs(groupName, cmd, status, msg){
        let group = this.groupConns.get(groupName);
        if(group){
            group.BroadcastArgs(cmd, status, msg);
        }
    }

    Broadcast(data){
        this.conns.forEach(function(value, key) {
            value.Send(data);
        });
    }

    BroadcastArgs(cmd, status, msg){
        this.conns.forEach(function(value, key) {
            value.SendArgs(cmd, status, msg);
        });
    }

    Ping(){
        this.conns.forEach(function(value, key) {
            value.SendArgs("ping", 0, "ping");
        });

        let that = this;
        setTimeout(function() { that.Ping(); }, this.pingTimer);       
    }

    Check(){
        this.unconns.forEach(function(value, key) {
            value.ToConnect();
        });

        let that = this;
        setTimeout(function() { that.Check(); }, this.checkTimer);
    }

    Start(){
        if(!this.isStarted){
            let that = this;

            setTimeout(function() { that.Ping(); }, this.pingTimer);
            setTimeout(function() { that.Check(); }, this.checkTimer);

            console.log("WsClientManager.Start ...");
        }
        this.isStarted = true;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值