Создание карты идентификаторов для сокетов и наоборот в Node.js - PullRequest
1 голос
/ 10 февраля 2012

Я пытаюсь управлять кучей соединений сокетов. Мое приложение - это http-сервер, который получает сообщения и передает их в сокет. Когда клиенты открывают соединение через сокет, они отправляют сообщение о соединении с идентификатором:

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

Затем приложение сохраняет этот идентификатор и сокет в картах id2socket и socket2id. При отключении пара сокет / идентификатор удаляется с карт.

Сообщение также будет содержать идентификатор, который указывает, что данные сообщения должны быть отправлены в сокет с этим идентификатором.

Это замечательно, и это прекрасно работает для одного открытого сокета. Однако, когда у меня открыто более одного сокета, а затем я закрываю сокет, это отключение стирает все с карты. Я думаю, что мое понимание сокетов в узле неполно - есть ли только один объект сокета, который используется в обратном вызове? Есть ли лучший способ управления подключениями и идентификаторами открытых сокетов?

стартовый сервер:

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

Телнет в:

>>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 устройство имеет идентификатор 123, сервер пока имеет это аппаратное обеспечение). Однако, как только вы закроете одно соединение, все сокетные соединения будут удалены из карты.

Вот мой код:

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 Ответ

1 голос
/ 10 февраля 2012

Объекты принимают строки только в качестве ключей для своих свойств.Как показывает ваш журнал, объект сокета преобразуется в строку "[object Object]".В результате сокет № 2 перезаписывает идентификатор из сокета № 1 в объекте, поскольку все сокеты преобразуются в один и тот же строковый ключ.Таким образом, в объекте всегда есть только одно свойство, потому что все сокеты сводятся к одному и тому же ключу.Когда вы пытаетесь удалить идентификатор для сокета # 2, отдельное свойство удаляется, а объект становится пустым.

Похоже, что вы хотите использовать настраиваемое свойство для каждого отдельного сокета при использовании в качестве ключа.Вы можете использовать WeakMap s для этого.WeakMap s допускают использование объектов в качестве ключей (в отличие от ключей только для строк), но, поскольку они относительно новые, они могут содержать ошибки на данный момент.

(Обратите внимание, что карта 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). </p>


* 0 и-0 являются исключениями, но вы все равно не должны использовать -0, потому что 0 === -0, поэтому трудно различать их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...