Socket.io在断开连接后无法正确触发事件。

3

我想用socket.io构建一个小游戏应用,其工作方式如下:

用户加载网站后,我使用generalConnection命名空间创建一个通用的socket。

app.generalSocket = io.connect('http://localhost/generalConnection');

目前我还没有在其中添加任何特殊事件,但我认为将其与第二个命名空间分开会更好。

当用户登录时,我调用一个函数来启动游戏连接(另一个命名空间)并绑定一些事件,我不会列出所有的事件,因为我认为这并不重要。

app.startGameSocket = function() {
    app.gameSocket = io.connect('http://localhost/gameConnection'); //game connection

    app.gameSocket.on("connect", function() {
        console.log("connected to the game socket");
    });
}

在服务器端,我有类似如下的代码:
var connectedPlayers = [];
var gameConnection = io.of('/gameConnection').on('connection', function (socket) {
    socket.on('disconnect', function () {
        //some stuff
    });
});

再次说明,我不认为需要列举所有事件,我只是解释一下它的工作原理。
它监听新玩家事件,创建新玩家,将其推送到connectedPlayers数组中,然后发送给连接到gameConnection命名空间的每个人。
用户列表会更新,所有人都很高兴。当用户关闭浏览器窗口时,我还可以监听其他事件(如断开连接),并适当地更新connectedPlayers数组。
当用户从游戏中注销时,我还必须断开gameConnection命名空间,在客户端上执行以下操作:
app.vent.on('logOut', function() {
    app.gameSocket.disconnect();
)};

注意我保持了 generalConnection 命名空间的开放性,只是断开了 gameConnection 命名空间。 如果用户注销或关闭窗口,它能很好地工作,会在服务器端触发 disconnect 事件,更新 connectedPlayers 数组并将其发送回已连接的玩家。
问题在于: 当用户: 1. 进入网站。 2. 登录游戏。 3. 注销。 4. 不刷新窗口而再次登录(再次触发 app.startGameSocket 函数)。 5. 在所有这些操作之后关闭窗口时,gameConnection 命名空间的 disconnect 事件不会在服务器上触发,列表也没有更新。
Node shell 显示:info - transport end (socket end),但不会触发 disconnect 事件。请帮忙 :)
我尝试过:
app.vent.on('logOut', function() {
    app.gameSocket.emit('forceDisconnect'); //force disconnect on the server side
    app.gameSocket.disconnect();
    app.gameSocket.removeAllListeners(); //tried to really kill disconnected socket
)};

但是没有结果。


我刚刚发现,我可以通过将app.gameSocket.disconnect();绑定到window.onbeforeunload事件来解决它。因此,当窗口关闭时,连接被断开,但我仍然希望了解出了什么问题。 - youbetternot
3个回答

1
你可以配置socket.io在窗口卸载时断开连接。
请参考Socket.io wiki中客户端的“同步卸载时断开连接”选项。该选项默认为false,如果启用它,应该可以解决你的问题。
app.gameSocket = io.connect('http://localhost/gameConnection', {'sync disconnect on unload':true}); //game connection

我曾尝试使用window.onbeforeunload做过类似的事情,但是我的解决方案和你的解决方案都没有完全解决它。如果您想了解更多信息,我已经回答了我的问题并提供了一些细节。 - youbetternot

1

Socket.io 不是很有趣!

在我的应用中,每个登出 > 登录的过程是

app.gameSocket = io.connect('http://localhost/gameConnection'); //game connection

所以像那样多次调用它会引起问题。我已将其更改为以下内容:

app.firstConnect = true;

app.startGameSocket = function(){
    if(app.firstConnect){
        app.gameSocket = io.connect('http://localhost/gameConnection'); //game connection
    }else{
        app.gameSocket.socket.reconnect();
    }
}

app.vent.on('logOut', function(){
    app.firstConnect = false;
});

我的问题已经解决了,但是socket.reconnect引入了另一个问题!您可以在此处阅读有关此问题的详细信息https://github.com/LearnBoost/socket.io/issues/430


1
当socket建立连接时,它通过socket参数来识别各个客户端。然后,所有其他事件都会分配给每个socket-client,在io.connection块下使用socket.on。每当任何客户端连接或断开连接时,它自己的socket事件(socket.on)就会被调用,并且socket.io会使用该socket参数和每个socket的id来进行标识。
示例:
io.sockets.on('connection', function(socket //unique client socket as parameter) {
 //code block
}

例如:

io.sockets.on('connection', function(socket) {
    //connect Me(socket)
    socket.on('connect', function() {
        console.log('disconnected')
    })
    //disconnect Me(socket)
    socket.on('disconnect', function() {
        console.log('disconnected')
    })
});

你的代码在做什么。
app.vent.on('logOut', function() {
    app.gameSocket.emit('forceDisconnect'); //force disconnect on the server side
    app.gameSocket.disconnect();
    app.gameSocket.removeAllListeners(); //tried to really kill disconnected socket
)};

它没有发出客户端特定套接字的断开事件。
app.gameSocket.emit('forceDisconnect'); //force disconnect on the server side

强制断开连接,但是断开谁?

你需要像这样的东西。

app.startGameSocket = function() {
    app.gameSocket = io.connect('http://localhost/gameConnection'); //game connection

    app.gameSocket.on("connect", function() {
        console.log("connected to the game socket");
    });

    //disconnect
    app.gameSocket.on("disconnect", function() {
        console.log("disconnected");
        //force disconnect/logout code
    });

    app.gameSocket.on('logOut', function() {
        //force disconnect/logout code
        app.gameSocket.emit('forceDisconnect'); //force disconnect on the server side
        app.gameSocket.disconnect();
        app.gameSocket.removeAllListeners(); //tried to really kill disconnected socket
    )};

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接