2012-02-18 24 views
7

Tôi có một máy chủ proxy quản lý một loạt các máy khách và cũng nói chuyện với một máy chủ http khác. Thư được đăng qua lại và hướng đến khách hàng. Khách hàng có thể và làm thời gian chờ, và máy chủ có chức năng nhịp tim (lặp lại cứ sau mỗi giây) gửi một nhịp tim đến tất cả các máy khách đang ở trong bản đồ của clientId đến kết nối socket.ngoại lệ socket.js đọc ETIMEDOUT - làm thế nào để tôi nắm bắt nó đúng cách? những gì về viết timeouts?

Tôi nhận được ngoại lệ 'đọc ETIMEDOUT' khi nhịp tim cố gắng nói chuyện với khách hàng không còn kết nối nhưng ai vẫn đang hoạt động. Tôi đã thử tạm thời thiết lập thời gian chờ của kết nối socket đến 2000ms với lý thuyết rằng trình xử lý sự kiện socket của tôi cho thời gian chờ sẽ bắt được điều này (trình xử lý sự kiện nằm trong phần máy chủ tcp), nhưng điều này đã không xảy ra. Phải mất nhiều nhịp đập để chết.

Một phần của vấn đề chắc chắn là sự thiếu hiểu biết về cách cấu trúc mã node.js, vì vậy nếu bạn có bất kỳ đề xuất nào, tôi rất cảm kích chúng.

Một câu hỏi khác là liệu có thể xử lý thời gian chờ đọc và ghi riêng biệt hay ít nhất là tách chúng ra. Những gì tôi thực sự muốn làm là có chức năng nhịp tim của tôi là một phần của máy chủ tcp và chỉ gửi một nhịp tim nếu nó đã không nghe từ khách hàng trong n giây nói, và chỉ gửi nhịp tim này một lần. Nếu chúng ta hết thời gian chờ, thì chúng ta sẽ phá hủy ổ cắm, nếu không chúng ta sẽ đợi lần nữa.

Cảm ơn!

>>$ node --harmony-weakmaps server.js 
Heartbeat: Sat Feb 18 2012 08:34:40 GMT+0000 (UTC) 
{ 
    sending keep_alive to id:00:00:00:00:00:10 socket:[object Object] 
} 
socket:received data: {"id":"00:00:00:00:00:10","m":"keep_alive","success":"true"} 

Heartbeat: Sat Feb 18 2012 08:35:40 GMT+0000 (UTC) 
{ 
    sending keep_alive to id:00:00:00:00:00:10 socket:[object Object] 
} 


socket:received data: {"id":"00:00:00:00:00:10","m":"keep_alive","success":"true"} 
node.js:201 
     throw e; // process.nextTick error, or 'error' event on first tick 
      ^
Error: read ETIMEDOUT 
    at errnoException (net.js:642:11) 
    at TCP.onread (net.js:375:20) 

Heartbeat chức năng kích hoạt thời gian chờ:

console.log("Starting heartbeat"); 
var beat_period = 60; 
setInterval(function() { 
    if(Object.keys(id2socket).length != 0){ 
     console.log("Heartbeat: " + new Date()); 
     //for (var key in id2socket) { 
     // console.log("\t"+key+"->"+id2socket[key]); 
     //} 
     console.log("{"); 
     for(var id in id2socket) { 
      var socket = id2socket[id]; 
      // don't want sockets to time out 
      socket.setTimeout(2000); // for heartbeat, set the timeout 
      try { 
       console.log("\tsending keep_alive to id:"+id+" socket:"+id2socket[id]); 
       socket.write('{"m":"keep_alive"}\r\n'); 
      } catch(Error) { 
       console.log("Heartbeat:Cannot find id:"+id); 
       removeSocketFromMap(id,socket); 
       // TODO: send message to API 
      } 
      socket.setTimeout(0); // no timeout 
     } 
     console.log("}"); 
    } 
}, beat_period * 1000); 

server.js:

// Launch Instructions 
// node --harmony-weakmaps server.js 

var net = require('net'); // tcp-server 
var http = require("http"); // http-server 
var querystring = require('querystring'); 

// Map of sockets to clients 
var id2socket = new Object; 
var socket2id = new WeakMap; // allows us to use object as key to hash 

// Test for client: 
// {"id":"123","m":"add"} // establishes connection and puts client into id2socket map 
// {"id":"123","m":"test"} // sends a message through to API 

// HTTP:POST outbound function 
// http://www.theroamingcoder.com/node/111 
function postOut(dataToPost){ 
    try{ 
     console.log("postOut msg:"+JSON.stringify(dataToPost)); 
    } catch (Error) { 
     console.log("postOut error:"+Error); 
    } 

    var post_domain = '127.0.0.1'; 
    var post_port = 80; 
    var post_path = '/cgi-bin/index3.py'; 

    var post_data = querystring.stringify({ 
      'act' : 'testjson', 
      'json' : JSON.stringify(dataToPost) 
    }); 
    console.log("post_data:"+post_data); 

    var post_options = { 
     host: post_domain, 
     port: post_port, 
     path: post_path, 
     method: 'POST', 
     headers: { 
     'Content-Type': 'application/x-www-form-urlencoded', 
     'Content-Length': post_data.length 
     } 
    }; 
    var post_req = http.request(post_options, function(res) { 
     res.setEncoding('utf8'); 
     res.on('data', function (chunk) { 
     console.log('Response:data: ' + chunk); 
     }); 
    }); 

    // Handle various issues 
    post_req.on('error', function(error) { 
     console.log('ERROR' + error.message); 
     // If you need to go on even if there is an error add below line 
     //getSomething(i + 1); 
    }); 
    post_req.on("response", function (response) { 
     console.log("Response:response:"+response); 
    }); 

    // write parameters to post body 
    post_req.write(post_data); 
    post_req.end(); 
} 

function removeSocketFromMap(id,socket){ 
    console.log("removeSocketFromMap socket:"+socket+" id:"+id); 
    delete id2socket[id]; 
    socket2id.delete(socket); 
    //TODO: print map??? 
    console.log("socketmap {"); 
    for (var key in id2socket) { 
     console.log("\t"+key+"->"+id2socket[key]); 
    } 
    console.log("}"); 
} 

// Setup a tcp server 
var server_plug = net.createServer(

    function(socket) { 

     // Event handlers 
     socket.addListener("connect", function(conn) { 
      console.log("socket:connection from: " + socket.remoteAddress + ":" + socket.remotePort + " id:"+socket.id); 
     }); 

     socket.addListener("data", function(data) { 
      console.log("socket:received data: " + data); 
      var request = null; 
      try { 
       request = JSON.parse(data); 
      } catch (SyntaxError) { 
       console.log('Invalid JSON:' + data); 
       socket.write('{"success":"false","response":"invalid JSON"}\r\n'); 
      } 

      if(request!=null){ 
       response = request; // set up the response we send back to the client 

       if(request.m=="keep_alive"){ // HACK for keep alive 
        // Do nothing 
       } else if(request.m !== undefined && request['id'] !== undefined){ // hack on 'id', id is js obj property 
        if(request.m == 'connect_device' || request.m == 'add'){ 
         console.log("associating uid " + request['id'] + " with socket " + socket); 
         id2socket[request['id']] = socket; 
         socket2id.set(socket, request['id']); 
        } 
        postOut(request); 
        socket.write(JSON.stringify(response)+"\r\n"); 
       } else if(request['id'] !== undefined){ 
        postOut(request); 
        socket.write(JSON.stringify(response)+"\r\n"); 
       } else { 
        response['content'] = "JSON doesn't contain m or id params"; 
        socket.write(JSON.stringify(response)+"\r\n"); 
       } 
      } else { 
       console.log("null request"); 
      } 

     }); 

     socket.on('end', function() { 
      id = socket2id.get(socket); 

      console.log("socket:disconnect by id " + id); 
      removeSocketFromMap(id,socket); 
      socket.destroy(); 
     }); 

     socket.on('timeout', function() { 
      id = socket2id.get(socket); 

      console.log('socket:timeout by id ' + id); 
      removeSocketFromMap(id,socket); 
      socket.destroy(); 
     }); 

     // handle uncaught exceptions 
     socket.on('uncaughtException', function(err) { 
      id = socket2id.get(socket); 

      console.log('socket:uncaughtException by id ' + id); 
      removeSocketFromMap(id,socket); 
      socket.destroy(); 
     }); 

    } 
); 
server_plug.on('error', function (error) { 
    console.log('server_plug:Error: ' + error); 
}); 

// Setup http server 
var server_http = http.createServer(
    // Function to handle http:post requests, need two parts to it 
    // http://jnjnjn.com/113/node-js-for-noobs-grabbing-post-content/ 
    function onRequest(request, response) { 
     request.setEncoding("utf8"); 
     request.content = ''; 

     request.on('error', function(err){ 
      console.log("server_http:error: "+err); 
     }) 

     request.addListener("data", function(chunk) { 
      request.content += chunk; 
     }); 

     request.addListener("end", function() { 
      console.log("server_http:request_received"); 

      try { 
       var json = querystring.parse(request.content); 

       console.log("server_http:received_post {"); 
       for(var foo in json){ 
        console.log("\t"+foo+"->"+json[foo]); 
       } 
       console.log("}"); 

       // Send json message content to socket 
       if(json['json']!=null && json['id']!=null){ 
        id = json['id']; 
        try { 
         var socket = id2socket[id]; 
         socket.write(json['json']+"\r\n"); 
        } catch (Error) { 
         console.log("Cannot find socket with id "+id); 
        } finally { 
         // respond to the incoming http request 
         response.end(); 
         // TODO: This should really be in socket.read! 
        } 
       } 
      } catch(Error) { 
       console.log("JSON parse error: "+Error) 
      } 
     }); 

     request.on('end', function() { 
      console.log("http_request:end"); 
     }); 

     request.on('close', function() { 
      console.log("http_request:close"); 
     }); 
    } 
); 
server_http.on('error', function (error) { 
    console.log('server_http:Error: ' + error); 
}); 

// Heartbeat function 
console.log("Starting heartbeat"); 
var beat_period = 60; 
setInterval(function() { 
    if(Object.keys(id2socket).length != 0){ 
     console.log("Heartbeat: " + new Date()); 
     //for (var key in id2socket) { 
     // console.log("\t"+key+"->"+id2socket[key]); 
     //} 
     console.log("{"); 
     for(var id in id2socket) { 
      var socket = id2socket[id]; 
      // don't want sockets to time out 
      socket.setTimeout(2000); // for heartbeat, set the timeout 
      try { 
       console.log("\tsending keep_alive to id:"+id+" socket:"+id2socket[id]); 
       socket.write('{"m":"keep_alive"}\r\n'); 
      } catch(Error) { 
       console.log("Heartbeat:Cannot find id:"+id); 
       removeSocketFromMap(id,socket); 
       // TODO: send message to API 
      } 
      socket.setTimeout(0); // no timeout 
     } 
     console.log("}"); 
    } 
}, beat_period * 1000); 



// Fire up the servers 
//var HOST = '127.0.0.1'; // just local incoming connections 
var HOST = '0.0.0.0'; // allows access to all external IPs 
var PORT = 5280; 
var PORT2 = 9001; 

// accept tcp-ip connections 
server_plug.listen(PORT, HOST); 
console.log("TCP server listening on "+HOST+":"+PORT); 

// accept posts 
server_http.listen(PORT2); 
console.log("HTTP server listening on "+HOST+":"+PORT2); 

EDIT:

Tôi có nên sử dụng .Trên (sự kiện, callback) vs .onlistener (sự kiện, gọi lại)?

UPDATE:

đó không làm việc, tôi đã thay đổi những thứ trong tcp_server cho tất cả add_listener trong nhịp tim như .Trên. Vẫn không nắm bắt được lỗi và thổi bay và nói rằng tôi đã thêm quá nhiều người nghe.

+0

Tôi gặp vấn đề tương tự, không thể nắm bắt ngoại lệ ETIMEDOUT. Bạn đã giải quyết nó? – takluiper

Trả lời

1

Đối với vấn đề ngoại lệ ETIMEDOUT, bạn đã thử lắng nghe một ngoại lệ chưa bắt đầu trên chính quy trình đó chưa?

process.on('uncaughtException', function (err) { 
    console.log('Caught exception: ' + err); 
}); 

Xem tài liệu ở đây: http://nodejs.org/docs/latest/api/process.html#event_uncaughtException_

+3

Không khuyến khích https://github.com/joyent/node/issues/2582 – corpix

+1

Đảm bảo bạn có một ổ cắm phù hợp.on ('error') handler là cách thực hành tốt nhất (xem câu trả lời của EdH), nhưng điều này rất hay để biết, và có thể ngăn cản một trình xử lý lỗi bị lãng quên làm rơi toàn bộ máy chủ với nhiều máy khách được kết nối. Đó là tính năng "sử dụng rủi ro của riêng bạn". –

5

Thứ nhất, nó một chút khó khăn để nói nếu cấu trúc của bạn là đúng nếu không có sự hiểu biết hơn về bối cảnh của mã của bạn ...

Hãy thử thêm

socket.on('error', function() { 
    id = socket2id.get(socket); 

    console.log('socket:timeout by id ' + id); 
    removeSocketFromMap(id,socket); 
    socket.destroy(); 
} 

với chức năng ẩn danh trong net.CreateServer. ETIMEDOUT là lỗi hệ thống, và node.js chỉ báo cáo nó. Nó có thể không được gây ra bởi chỉ là một 'thời gian chờ' điển hình. Bạn nói rằng nó được gây ra bởi các Hearbeat viết, nhưng có vẻ như TCP.read là nguồn gốc. Nó có thể là một ổ cắm nửa kín.

Các vấn đề liên quan