如何使用node.js net.Socket

时间:2016-02-27 12:12:34

标签: node.js postgresql sockets

我能够将一条启动消息发送到我运行的PostgreSQL服务器并从该服务器获得响应。我得到了ParameterStatus消息。问题是我从来没有得到任何类型的身份验证消息。我的问题是:为什么服务器永远不会向我发送任何类型的身份验证消息?

下面我将向您展示我的代码片段,用于了解协议的启动部分如何工作,以及为调试输出的几行(希望您甚至不必阅读我的代码),我认为是来自PostgreSQL文档的有用信息,用于理解我的问题,以及我发现对可视化协议有用的另一个资源。

这是我的代码:

var net = require('net');
var BlueBird = require('bluebird');
var Buffer = require('buffer').Buffer;


var createStartupMessage = function(user_name, database_name){

    var buffer_size = 22 + user_name.length + 1 + database_name.length + 1 + 1;
    var StartUpMessage = new Buffer(buffer_size);
    var position_in_buffer = 0;

    StartUpMessage.writeUInt32BE(buffer_size, 0);
    position_in_buffer += 4;

    StartUpMessage.writeUInt32BE(196608, position_in_buffer); //version 3.0
    position_in_buffer += 4;

    position_in_buffer = addMessageSegment(StartUpMessage, "user", position_in_buffer);
    position_in_buffer = addMessageSegment(StartUpMessage, user_name, position_in_buffer);

    position_in_buffer = addMessageSegment(StartUpMessage, "database", position_in_buffer);
    position_in_buffer = addMessageSegment(StartUpMessage, database_name, position_in_buffer);

    //Add the last null terminator to the buffer
    addNullTerminatorToMessageSegment(StartUpMessage, position_in_buffer);

    console.log("The StartUpMessage looks like this in Hexcode: " + StartUpMessage.toString('hex'));
    console.log("The length of the StartupMessage in Hexcode is: " + StartUpMessage.toString('hex').length);

    return StartUpMessage;

    };


var addMessageSegment = function(StartUpMessage, message_segment, position_in_buffer){

    var bytes_in_message_segment = Buffer.byteLength(message_segment);

    StartUpMessage.write(message_segment, position_in_buffer, StartUpMessage - position_in_buffer, 'utf8');
    position_in_buffer = position_in_buffer + bytes_in_message_segment;

    position_in_buffer = addNullTerminatorToMessageSegment(StartUpMessage, position_in_buffer);

    return position_in_buffer;

};


var addNullTerminatorToMessageSegment = function(StartUpMessage, position_in_buffer){

    StartUpMessage.writeUInt8(0, position_in_buffer);
    position_in_buffer = position_in_buffer + 1;

    return position_in_buffer;

};

//Here is where everything starts. The functions above are called within this BlueBird Promise.
BlueBird.coroutine(function* () {

    var host = "127.0.0.1";
    var port = "5432";
    var idle_timeout = 10000;

    var MySocket = new net.Socket();
    MySocket.setTimeout(idle_timeout);

    var StartUpMessage = createStartupMessage("testusertwo", "testdatabasetwo");

    var data = yield new Promise(

        function resolver(resolve, reject) {

            var number_of_responses = 0;
            var number_of_responses_to_wait_for = 2;

            MySocket.on('connect', function () {
                var message = StartUpMessage.toString("utf8");
                var flushed = MySocket.write(message, "utf8");
                console.log("Message flushed to kernel: " + flushed);
            });

            MySocket.on('data', function (data) {  

                console.log("The response from the server is: " + data.toString('utf8'));
                console.log("----This Line Divides the Response Below from the Response Above----");

                if( number_of_responses !== number_of_responses_to_wait_for){
                    number_of_responses += 1;
                } else {
                    resolve(data);
                }

            });

            MySocket.on('error', function (error) {
                reject(error);
            });

            MySocket.connect(port, host);

        }

        );

    return data;

})()
    .then(function (data) {

        return data;

  })
    .catch(function (error) {

        console.error(error);

  });

这些是我的代码输出用于调试目的的几行。它显示了我发送到服务器的初始utf-8编码消息的十六进制代码表示(启动消息格式通过底部的链接显示在幻灯片9上)。然后它显示服务器响应。

在此之后我的程序挂起等待我等待它发送一个Authentication类消息。在启动消息中,为方便起见,我将前两个32位Big Endian整数和所有空终止符加粗。还有,?最后的标记(在?M2 \ ?? ZI中)实际上是来自utf-8的那些钻石问号,并且这个结束部分也在每次运行时都会发生变化。我不知道为什么。

我的代码的一些输出:

StartUpMessage在Hexcode中显示如下:

 **0000003300030000**75736572**00**746573747573657274776f**00**6461746162617365**00**74657374646174616261736574776f**0000**

服务器的响应是:

  

Sapplication_nameSclient_encodingUTF8SDateStyleISO,MDYSinteger_datetimesonSntervalStylepostgresSis_superuseroffSserver_encodingUTF8Sserver_version9.5.0S& session_authorizationtestusertwoS#standard_conforming_stringsonSTimeZoneUS / EasternK                                                                                                                 ?M2 \ ?? ZI

我认为这是Postgresql文档中的相关信息:

  

50.2.Message Flow.1。开始:

     

要开始会话,前端会打开与服务器的连接并发送启动消息。

     

验证周期以服务器拒绝连接尝试(ErrorResponse)或发送AuthenticationOk结束。

本节还说明其他一些内容,如果不需要密码并且一切都没有错误,我应该获得列出的许多身份验证消息之一(例如AuthenticationCleartextPassword消息)或AuthenticationOk。如果有错误,那么我应该收到ErrorResponse消息。

  

50.5.Message格式:

在本节中,指出如果服务器响应中的第一个字节为“S”,则将Message分类为ParameterStatus消息。

在本节中,它还指出,如果服务器响应中的第一个字节为“R”,则将消息归类为“身份验证”消息。

我找到了有用的资源:

我认为这是可视化消息流协议的非常好的资源。作者的名字是Jan Urban ski。在幻灯片9上,显示了启动数据包。我发现的唯一的东西(无论如何都是node.js)需要在之前有另一个空终止符框。 。 。框。

https://www.pgcon.org/2014/schedule/attachments/330_postgres-for-the-wire.pdf

1 个答案:

答案 0 :(得分:0)

在查看Wireshark之​​后,我意识到我收到了一条身份验证消息('R'类型的消息)。问题是我正在从服务器中错误地解析数据。我立即将它转换为UTF8字符串。在将任何数据转换为UTF8之前,需要根据消息格式解析数据。这是因为格式不仅仅是一串串起来的字符。它们包括32位大端整数和16位大端整数。