• 在cocos2d-js里实现socket.io前后端实时通信


    Socket.io
    Socket.io是个用来做客户端和服务端的实时双向端口通信的javascript库,它分前端库部分和后台的node.js部分。
    用它适合实现聊天或多人对战等实时性强的任务,它会在客户端和后台间建立一个socket链接,双向data streaming或messaging; 相比之下,常见的HTTP请求的header相当大影响传输实时性,而且只能从客户端往服务器发请求,服务器无法实时向客户端推送。
    
    在cocos2d-js里使用socket.io
    cocos2d-x C++和javascript的测试代码里都有socket.io的例子。 我用的是版本3.7,js的例子在js-test/src/ExtensionsTest/NetworkTest/SocketIOTest.js里。 可运行一下会发现它里面提供的后台endpoint链接是坏的, 于是我这儿就自己搭一遍后台。
    
    Socket.io的最佳最简单的参考是官网上的聊天例子。
    http://socket.io/get-started/chat/
    
    用到的库
    cocos2d-x 3.7 (内带javascript版的)用于前端
    node.js v0.10.29
    socket.io v0.9.9 (这里我用0.9x版的,1.x版会有点兼容性问题)
    后台 Server side
    建立工作文件夹server, 在里面添加package.json定义node.js要用的包:
    * package.json
    
    {
      "name": "socketio-server",
      "version": "0.0.1",
      "description": "for socket.io test",
      "dependencies": {
        "socket.io": "0.9.5"
      }
    }
    添加后台的node.js代码,这里建立连接并定义使用端口3000.
    * socketio-server.js
    
    server = require('http').Server();
    var socketIO = require('socket.io');
    var io = socketIO.listen(server);
    var counter = 0;
    
    io.sockets.on('connection', function(socket){
        console.log("connected!");
    
        io.sockets.emit('connected', { value: "server ok" });
    
        socket.on('handshake', function(data){
            console.log("receive handshake from client : " + data.value);
        });
    
        socket.on('message', function(data){
            console.log("receive message from client : " + data.value);
            io.sockets.emit('confirmed', { value: "confirmed from server" });
        });
    
        socket.on('disconnect', function(){
            console.log("disconnect");
        });
    });
    server.listen(3000);
    
    setInterval(function() {
        counter++;
        console.log("Periodic broadcast:" + counter);
        io.sockets.emit('broadcast', { value: "count:" + counter });
    }, 1000)
    其实就是用on函数监听来自前端的事件然后设置回调就行了:
    
    socket.on('some signal', function(data){
        console.log("receive message from client : " + data.value);
    });
    向客户端发送信息用emit:
    
    io.sockets.emit('connected', { value: "server ok" });
    前端 Front end
    建一个SocketTest的Layer:
    
    window.io;
    var SocketIO = SocketIO || window.io;
    
    var SocketTestLayer = cc.Layer.extend({
        _statusLabel:null,
        _broadcastLabel:null,
        _sioclient:null,
        ctor:function () {
            //////////////////////////////
            // 1. super init first
            this._super();
            this.initLayer();
        },
        initLayer:function() {
    
            var menuRequest = new cc.Menu();
            menuRequest.setPosition(cc.p(0, 0));
            this.addChild(menuRequest);
    
            var vspace = 80;
    
            // Test to create basic client in the default namespace
            var labelSIOClient = new cc.LabelTTF("Open SocketIO Client", "Arial", 30);
            var itemSIOClient = new cc.MenuItemLabel(labelSIOClient, this.onMenuSIOClientClicked, this);
            itemSIOClient.attr({x:200, y:SCR_SIZE_H - 150});
            menuRequest.addChild(itemSIOClient);
    
            var labelMessage = new cc.LabelTTF("Send message", "Arial", 30);
            var itemSendMessage = new cc.MenuItemLabel(labelMessage, this.onSendMessageClicked, this);
            itemSendMessage.attr({x:200, y:SCR_SIZE_H - 150 - vspace});
            menuRequest.addChild(itemSendMessage);
    
            // label
            this._broadcastLabel = new cc.LabelTTF("No broadcast", "Arial", 24);
            this._broadcastLabel.attr({x:300, y:100});
            this.addChild(this._broadcastLabel);
        },
        onSocketReceive: function(eventname, callback) {
            this._sioclient.on(eventname, function(data) {
                if (cc.sys.isMobile) {
                    var obj = JSON.parse(data);
                    data = obj.args[0];
                }
                callback(data);
            });
        },
        socketEmit:function (eventname, data) {
            if (cc.sys.isMobile) {
                this._sioclient.emit(eventname, JSON.stringify([data]));
            }
            else {
                this._sioclient.emit(eventname, data);
            }
        },
        onMenuSIOClientClicked:function() {
            this._sioclient = SocketIO.connect("http://192.168.0.5:3000");
    
            this._sioclient.on("connected", function() {
                cc.log("Connected");
                var msg = "Hi I am client!";
                this.emit("handshake", JSON.stringify([{value:msg}]));
            });
    
            this._sioclient.on("confirmed", function(data) {
                cc.log("Receive from server: " + data.value + "@ " + new Date());
            });
    
            this.onSocketReceive("broadcast", function(data) {
                var msg = "Receive broadcast: " + data.value;
                cc.log(msg);
                this._broadcastLabel.setString(msg); // in order to access 'this', bind(this) is neccessary
            }.bind(this));
        },
        onSendMessageClicked:function() {
            cc.log("emit message");
            var msg = "Message from client."
            this.socketEmit("message", {value:"nice"});
        }
    });
    
    var SocketTestScene = cc.Scene.extend({
        onEnter:function () {
            this._super();
            var layer = new SocketTestLayer();
            this.addChild(layer);
        }
    });
    假设后台服务器地址是192.168.0.5
    
    SocketIO.connect("http://192.168.0.5:3000");
    前端的收发方式和后台的写法一样,用on监听后台来的消息用emit向后台推消息。
    但要注意浏览器和native的js-binding在解析消息的数据的行为有些区别,所以我写了onSocketReceive和socketEmit用来区分浏览器和native:
    
        onSocketReceive: function(eventname, callback) {
            this._sioclient.on(eventname, function(data) {
                if (cc.sys.isMobile) {
                    var obj = JSON.parse(data);
                    data = obj.args[0];
                }
                callback(data);
            });
        },
        socketEmit:function (eventname, data) {
            if (cc.sys.isMobile) {
                this._sioclient.emit(eventname, JSON.stringify([data]));
            }
            else {
                this._sioclient.emit(eventname, data);
            }
        },

    博主长期对外收徒,欢迎咨询。
    《编程语言设计和实现》《MUD游戏开发》《软件破解和加密》《游戏辅助外挂》《JAVA开发》 以上课程非诚勿扰!



    =================================
    QQ:184377367
    GOLang Q群:6848027
    电子电路入门群 436173132
    C/C++/QT群 1414577
    单片机嵌入式群 306312845
    MUD/LIB/巫师交流群 391486684
    java/springboot/hadoop/ 群 4915800
    WEB前端开发交流群 214737701
    操作系统研发群:15375777
    Linux公社Q群:812742841
    汇编/辅助/破解新手群:755783453
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    《大话设计模式》ruby版代码:工厂方法模式
    《大话设计模式》ruby版代码:代理模式
    redis ruby客户端学习(一)
    《大话设计模式》ruby版代码:装饰模式
    打卡2
    打卡1
    分块题集
    2018 Multi-University Training Contest 7
    2018 Multi-University Training Contest 6
    2018 Multi-University Training Contest 4
  • 原文地址:https://www.cnblogs.com/cfas/p/14414322.html
Copyright © 2020-2023  润新知