2012-02-10 10 views
0

ソケット接続の束を管理しようとしています。私のアプリは、基本的に投稿を受け取り、これらをソケットに渡すhttpサーバです。クライアントがソケット接続を開くと、彼らは、IDと接続メッセージを送信:Node.jsのソケットとソケットのマップの作成

{"m":"connect","id":"1"} 

アプリは、その後id2socketとsocket2idマップでこのIDとソケットが保存されます。切断すると、ソケット/ IDペアがマップから削除されます。

投稿には、そのIDのソケットに投稿データを送信する必要があることを示すIDも含まれます。

これは素晴らしいことですが、これは単一のオープンソケットでうまく動作します。しかし、複数のソケットを開いていて、ソケットを閉じると、その接続がマップからすべて削除されます。私は、ノード内のソケットの理解が不完全であると思います - コールバックで使用されるソケットオブジェクトは1つだけですか?私のオープンソケット接続とIDを管理する良い方法はありますか?

開始サーバ:

>>node server.js 
TCP server listening on 127.0.0.1:5280 
HTTP server listening on 127.0.0.1:9002 

のtelnetで:接続後の

>>telnet localhost 5280 
Trying 127.0.0.1... 
Connected to localhost. 
Escape character is '^]'. 
{"m":"connect","id":"123"} 
{"m":"connect","id":"123","success":"true"} 

サーバー:

>>Connection from 127.0.0.1:57572 
received data: {"m":"connect","id":"123"} 

id: 1 
m: connect 
associating uid 1 with socket [object Object] 

ポストを実行します。

python post.py {"foo":"bar"} 

これはいくつかのオープンソケットでうまくいきます(1つのデバイスがID123であれば、サーバは現在このハードワイヤードを持っています)。ただし、1つの接続を閉じると、すべてのソケット接続がマップから削除されます。

は、ここに私のコードです:

Pythonスクリプトポスト行うには:

import sys 
import json 
import httplib, urllib, urllib2 

values = json.loads('{"foo":"bar"}') 
headers = {"Content-type": "application/json"} 

conn = httplib.HTTPConnection('127.0.0.1', 9002) 
headers = {"Content-type": "application/json"} 
conn.request("POST", "", json.dumps(values), headers) 
response = conn.getresponse() 

print "response.status: "+response.status 
print "response.reason: "+response.reason 
print "response.read: "+response.read() 
conn.close() 

ポスト上のデバイスにデータを送信するためにハードワイヤードノードサーバ(HTTPおよびTCP)、 '123':

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

// Map of sockets to devices 
var id2socket = new Object; 
var socket2id = new Object; 

// Setup a tcp server 
var server_plug = net.createServer(function(socket) { 

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

    socket.addListener("data", function(data) { 
     console.log("received data: " + data); 
     try { 
      request = JSON.parse(data); 

      response = request; 
      if(request.m !== undefined && request['id'] !== undefined){ // hack on 'id', id is js obj property 
       console.log("id: "+request['id']); 
       console.log("m: "+request.m); 
       if(request.m == 'connect'){ 
        console.log("associating uid " + request['id'] + " with socket " + socket); 
        id2socket[request['id']] = socket; 
        socket2id[socket] = request['id']; 
        response.success = 'true'; 
       } else { 
        response.success = 'true'; 
       } 
      } 
      socket.write(JSON.stringify(response)); 
     } catch (SyntaxError) { 
      console.log('Invalid JSON:' + data); 
      socket.write('{"success":"false","response":"invalid JSON"}'); 
     } 
    }); 

    socket.on('end', function() { 
     id = socket2id[socket] 
     console.log("socket disconnect by id " + id); 

     // wipe out the stored info 
     console.log("removing from map socket:"+socket+" id:"+id); 
     delete id2socket[id]; 
     delete socket2id[socket]; 
    }); 

    socket.on('timeout', function() { 
     console.log('socket timeout'); 
    }); 

}); 

// 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.addListener("data", function(chunk) { 
      request.content += chunk; 
     }); 

     request.addListener("end", function() { 
      console.log("post received!"); 
      //console.log("Request received: "+request.content); 


      if (request.method == 'POST') { 
       //var json = qs.parse(request.content); 
       //console.log("Post: "+json); 

       // HACK TO TEST STUFF: 
       // send a message to one of the open sockets 
       try { 
        var socket = id2socket['123']; //hardwired 
        socket.write('{"m":"post"}'); 
       } catch (Error) { 
        console.log("Cannot find socket with id "+'123'); 
       } 
      } 
     }); 
    } 
); 


// Fire up the servers 
var HOST = '127.0.0.1'; 
var PORT = 5280; 
var PORT2 = 9002; 

server_plug.listen(PORT, HOST); 
console.log("TCP server listening on "+HOST+":"+PORT); 

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

答えて

1

オブジェクトは、プロパティのキーとして文字列を取ります。あなたのログが示すように、ソケットオブジェクトは文字列"[object Object]"に変換されます。その結果、すべてのソケットが同じ文字列キーに変換されるので、ソケット#2はオブジェクトのソケット#1からのidを上書きします。したがって、オブジェクトには常にすべてのソケットが同じキーになるため、プロパティは1つしかありません。ソケット#2のIDを削除しようとすると、単一のプロパティが削除され、オブジェクトは空です。

キーとして使用すると、個別のソケットごとにカスタムプロパティが必要なようです。これにはWeakMapを使用できます。 WeakMapは、(文字列のみのキーとは対照的に)オブジェクトをキーとして許可しますが、それらは比較的新しいので、現時点ではバグを含んでいる可能性があります。

(番号がうまく文字列に変換され、各番号は、独自の、異なる文字列表現*を有しているのでid2socketマップは単に、普通のオブジェクトとすることができることに留意されたいです。次のようWeakMap Sを使用)

は次のとおりです。

var socket2id = new WeakMap; // as if you were doing: var socket2id = {}; 
socket2id.set(socket, id); // as if you were doing: socket2id[socket] = id; 
socket2id.get(socket);  // as if you were doing: socket2id[socket]; 
socket2id.delete(socket); // as if you were doing: delete socket2id[socket]; 

node --harmony(> = 0.7)またはnode --harmony_weakmaps(< = 0.6)で実行するようにしてください。


*0-00 === -0、それはそれらの間で異なることは困難ですので例外ですが、あなたはとにかく-0を使用すべきではありません。

関連する問題