为啥我的 websocket 在几分钟后关闭?

Posted

技术标签:

【中文标题】为啥我的 websocket 在几分钟后关闭?【英文标题】:Why does my websocket close after a few minutes?为什么我的 websocket 在几分钟后关闭? 【发布时间】:2015-04-11 14:50:33 【问题描述】:

我在服务器端使用带有 node.js 的 ws,在客户端使用常规的 WebSocket API。来回打开连接和消息几次工作正常。但是套接字总是在一两分钟后关闭。他们不应该坚持吗?我做错了吗?

我的服务器是托管在 heroku 上的 node.js。我刚刚使用foreman start(在本地运行服务器的heroku工具)再次在本地进行了测试,并且套接字根本没有意外关闭,所以这可能是heroku的错误配置。无论如何,这是一个相关的代码示例,为简洁起见省略了一些函数。

我正在 OSX Yosemite 上的 Chrome 中测试该应用程序,但在 Windows 7 上的 Chrome 中针对生产环境运行时看到了相同的行为。

服务器:

// Client <-> Host Protocol functions.  Move to a different file so that they can be shared.
var C2H_SIGNAL_TYPE_REGISTER = "register";

var H2C_SIGNAL_WELCOME = "welcome";
var H2C_SIGNAL_TYPE_ERROR = "error";
var H2C_SIGNAL_TYPE_PEER_ADDED = "peer_joined";
var H2C_SIGNAL_TYPE_PEER_LEFT = "peer_left";

// Update channel endpoint names.
var UPDATE_ENDPOINT_PEERS = "/peers";

// Create a signal message with all asociated default properties.
// Signal senders should create this object and update it accordingly when
// building a signal message to send to a peer.
function createHostMsg(type)

    var msg =  signalType: type ;

    if ( type == H2C_SIGNAL_WELCOME ) 
        // Since we're sending a welcome message, we need to provide a list
        // of currently connected clients.
        msg.peers = ;
        for ( var addr in clients ) 
            console.log("addr " + addr);
            var c = clients[addr].description;
            if ( c && c.id ) 
                msg.peers[c.id] = c;
            
        
    

    return msg;


// require modules. 
var express = require('express');
var http = require('http');
var bodyParser = require('body-parser');
var multer = require('multer');

// Tracks connected peers.
var clients =  ;

// 1.  Configure the application context settings.
var app = express();
app.enable('trust proxy');
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json()); // parse json
app.use(bodyParser.urlencoded( extended: true )); // for parsing application/x-www-form-urlencoded
app.use(multer()); // for parsing multipart/form-data

// a. configure http routers.  these will handle requests coming from app.
app.set('port', (process.env.PORT || 5000));
app.get('/app', peerApp);
app.get('/script/:name', publicScriptRouter);

// 2.  Create the http server itself, passing app to be the request handler.
// app will handle routing and multiplexing of incoming requests to different
// route middleware handlers.
var http = require('http');
var WebSocketServer = require("ws").Server
var httpServer = http.createServer(app);
httpServer.listen( app.get('port') );

// 3.  Create one of these for all socket endpoints.
var wss = new WebSocketServer(  server: httpServer, path: UPDATE_ENDPOINT_PEERS  );

wss.on("connection", function(webSocket) 

    // 1.  Associate the socket with the remote address it came from.
    var remoteAddress = webSocket._socket.remoteAddress;
    var remotePort = webSocket._socket.remotePort;
    var clientConnID = remoteAddress + ":" + remotePort;

    var exists = clients[clientConnID] != null;
    if ( exists ) 
        console.log("socket server connection: associating new connection from %s with registered peer.", clientConnID);
        clients[clientConnID].socket = webSocket;
     else 
        console.log("socket server connection: associating new connection from %s with unregistered peer.", clientConnID);
        clients[clientConnID] =  description: null, socket: webSocket ;
       

    // 2.  Hook up handlers for communication over this particular socket.
    webSocket.on("message", function(data, flags) 
        processMessage(webSocket, data, flags);
    );

    webSocket.on("close", function() 
        // Praise satin for closures!!
        removePeer(clientConnID);
    );

);

// Transduce the message and handle it accordingly.
function processMessage(socket, data, flags)

    var msg = JSON.parse(data);
    if ( !msg.signalType ) 

        var msg = createHostMsg( H2C_SIGNAL_TYPE_ERROR );
        msg.errStr = "message_malformed";
        socket.send( JSON.stringify( msg ) );

     else if ( msg.signalType == C2H_SIGNAL_TYPE_REGISTER ) 
        handleRegistration(socket, msg);
    

客户:

function initSignalChannel()

    rtcPeer.channel = new WebSocket( location.origin.replace(/^http/, 'ws') + "/peers" );
    rtcPeer.channel.onmessage = updateChannelMessage;
    rtcPeer.channel.onopen = function(event)  
        console.log("remote socket opened");
    
    rtcPeer.channel.onclose = function(event) 
        console.log("host closed remote socket.");
    


function updateChannelMessage(event) 

    var msgObj = JSON.parse(event.data);

    if ( !msgObj || !msgObj.signalType ) 

        console.log("updateChannelMessage: malformed response!! %o", msgObj );

     else if ( msgObj.signalType == "welcome" ) 

        console.log("updateChannelMessage: received welcome from host.");
        handleWelcome(msgObj);

     else if ( msgObj.signalType == "peer_joined" ) 
        console.log("updateChannelMessage: received peer_joined from host.");
        if ( msgObj.peer.id == rtcPeer.description.id ) 
            console.log("updateChannelMessage: peer_joined: received notification that I've been added to the room. " + msgObj.peer.id);
            console.log(msgObj);
         else 
            console.log("updateChannelMessage: peer_joined: peer %s is now online.", msgObj.peer.id);
            console.log(msgObj);
            addRemotePeer( msgObj.peer );
        
    



function addRemotePeer(peerObj)

    remotePeers[peerObj.id] = peerObj;
    var ui = createPeerUIObj(peerObj);
    $("#connectedPeerList").append( ui );


function createPeerUIObj(peerObj)

    var ui = null;
    if ( peerObj ) 
        ui = $("<li></li>");
        var a = $("<a></a>");

        a.append("peer " + peerObj.id);
        ui.append(a);
        ui.click(function(event)  console.log("clicked"););
    

    return ui;


function handleWelcome(msgObj)

    if ( msgObj.id ) 

        console.log("updateChannelMessage: welcome: received id from host. " + msgObj.id);
        console.log(msgObj);
        rtcPeer.description.id = msgObj.id;

        for ( var p in msgObj.peers ) 
            addRemotePeer(msgObj.peers[p]);
        

     else 
        console.log("updateChannelMessage: malformed response.  no id.");
    

【问题讨论】:

发布你的node.js代码和你的客户端代码,没有它我们帮不了你 还值得描述一下您的服务器基础架构(托管设施、代理等),因为有些不允许长时间运行的非活动套接字。 看起来您安装了不支持 websocket 的防火墙或防病毒过滤器代理。但正如 Marco 和 jfriend00 已经说过的那样,了解您的代码和您的环境会很有用。 谢谢大家。整理一个适当的描述,很快就会回复你。欣赏它。 这几分钟连接是否空闲?空闲的 tcp 连接通常会被一端或另一端关闭。 【参考方案1】:

感谢大家的cmets。原来 jfriend00 有正确的答案,我只是没有意识到我使用的托管服务不允许保持连接。

从下面的论坛帖子中,解决方案是

您需要让您的客户端定期 ping 服务器以保持套接字处于活动状态。

不是最理想的情况,但确实可行。感谢您为我指明正确的方向。

【讨论】:

以上是关于为啥我的 websocket 在几分钟后关闭?的主要内容,如果未能解决你的问题,请参考以下文章

我的 OpsWorks 实例在关闭五分钟后自行启动 - 为啥?

为啥 websocket 在使用代码 1000 响应本机打开后立即关闭。(iOS)

为啥 MongooseIM 会在 60 秒后关闭 websocket 连接?

防止iOS在几分钟后杀死App

关于WebSocket的问题 为啥浏览器关闭后会出一下异常

MQTT over Secure Websockets 套接字在一分钟后关闭 - RabbitMQ