Предотвратить сокращение сообщения сокета - PullRequest
0 голосов
/ 07 мая 2018
function parseMessage (buff){
    let obs = [];

    let done = false;
    let offset = 0;
    let size_bytes = 4;
    while(!done){
        let message_size = buff.readUIntBE(offset, size_bytes);
        let message = buff.slice(size_bytes + offset, size_bytes + offset + message_size).toString('utf8');
        offset = size_bytes+offset+message_size;
        try {
            let o = JSON.parse(message.toString());
            if (o && typeof o === "object") {
                obs.push(o);
            }
        }
        catch (e) {winston.error(e);winston.error(message);}
        if(offset >= buff.length - 1){
            done = true;
        }
    }

    return obs;
};
client_socket.on('data', function (data) {console.log(parseMessage(data));});

Я использую сокеты для передачи строкового JSON с клиента на сервер. Строковому JSON предшествует 4 байта для описания размера сообщения. Я сталкиваюсь с ошибкой, когда после нескольких сообщений JSON не может быть проанализирован, потому что строка сообщения урезана (я думаю, что она отправляется в следующем событии data). Мой вопрос заключается в том, что, поскольку его прохождение через tcp-сокеты, сообщение может быть свернуто так же, как оно может быть чрезмерно расширенным (почему мне пришлось добавлять сообщение с его размером). Если так, у кого-нибудь есть какие-нибудь изящные решения, чтобы решить это?

Клиент написан на Perl. Я могу предоставить код для этого при необходимости, но я думаю, что эта часть верна.

Дополнительный вопрос: поскольку размер предварительно добавленного сообщения составляет 4 байта. Означает ли это, что мои сообщения могут содержать не более (2 ^ (4'bytes '* 8'bits / byte')) / 8'bits / char '= 536 870 912 символов или этот расчет неверен?

1 Ответ

0 голосов
/ 08 мая 2018

Это решение, которое я в итоге придумала

function tryParseJSON(message,fail_cb){
    try {
        let o = JSON.parse(message.toString());
        if (o && typeof o === "object") {
            return(o);
        }
    }
    catch (err) {
        fail_cb(err);

    }   
}

function parseMessage (active_message_buffer_size,active_message_buffer,buff){
    let obs = [];

    let done = false;
    let offset = 0;
    let size_bytes = 4;
    while(!done){

        if(!active_message_buffer.length){
            active_message_buffer_size = buff.readUIntBE(offset, size_bytes);
        }

        active_message_buffer = Buffer.concat([active_message_buffer,buff.slice(size_bytes + offset, size_bytes + offset + active_message_buffer_size)])

        if(active_message_buffer.length && (active_message_buffer.length === active_message_buffer_size)){

            let message = active_message_buffer.toString('utf8');

            let parsed_json = tryParseJSON(message,function(err){
                winston.error(err);
            });
            if(parsed_json){
                obs.push(parsed_json);
            }

            active_message_buffer = new Buffer(0);
        }

        offset = size_bytes+offset+active_message_buffer_size-1;

        if(offset >= (buff.length - 1)){
            done = true;
        }
    }

    return obs;
};

net.createServer(
    function(client_socket){
        let active_message_buffer = new Buffer(0);
        let active_message_buffer_size = null;
        client_socket.on('data',function(data){console.log(parseMessage(active_message_buffer_size,active_message_buffer,data)});
    }

);

Оно не идеально, поскольку не учитывает вероятность разделения первых 4 байтов.

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