无法理解协议定义

时间:2016-12-09 15:14:02

标签: c++ postgresql protocols

我正在阅读Postgresql有线协议,无法实现与spec所说的简单查询相关的部分:

Query (F)
  Byte1('Q')
    Identifies the message as a simple query.

  Int32
    Length of message contents in bytes, including self.

  String
    The query string itself.

我在C ++中提出了以下内容:

(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >) $0 = size=31 {
  [0] = 'Q'
  [1] = '\0'
  [2] = '\0'
  [3] = '\0'
  [4] = '\x1f'
  [5] = 's'
  [6] = 'e'
  [7] = 'l'
  [8] = 'e'
  [9] = 'c'
  [10] = 't'
  [11] = ' '
  [12] = '*'
  [13] = ' '
  [14] = 'f'
  [15] = 'r'
  [16] = 'o'
  [17] = 'm'
  [18] = ' '
  [19] = 'd'
  [20] = 'e'
  [21] = 'p'
  [22] = 'a'
  [23] = 'r'
  [24] = 't'
  [25] = 'm'
  [26] = 'e'
  [27] = 'n'
  [28] = 't'
  [29] = 's'
  [30] = '\0'
}

但我总是从服务器收到错误:

EJSERRORC08P01Minvalid message formatFpqformat.cL652Rpq_getmsgendETSFATALC08P01Minvalid frontend message type 0Fpostgres.cL484RSocketBackend

此时我已经厌倦了在服务器上抛出不同版本的这个向量来获得相同的结果,所以我假设我对规范的解释是错误的。你能用代码告诉我这是怎么做到的吗?不是算法生成消息,只是一个有效的消息。

1 个答案:

答案 0 :(得分:2)

由于您不会分享您的代码,我无法说出错的地方。

你的消息很好,除了长度应该是30('\x1e')而不是31('\x1f') - 根据the documentation,“消息类型字节”不应该被计算在内。

我在Linux上使用C进行了尝试,它对我有用。

我使用send()发送了带有PQsocket()的套接字的消息,我收到的回复包括:

  1. 描述列的 RowDescription 消息(类型'T')。

  2. 每个返回的列
  3. 一条 DataRow 消息(类型'D')。

  4. 关闭语句的一个关闭消息(类型'C')。

  5. 一个 ReadyForQuery (类型'Z')消息。

  6. 记录中,这是我使用的C代码:

    #include <libpq-fe.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    
    #define BUFSIZE 1000
    
    int main(int argc, char **argv) {
        /* PostgreSQL database connection */
        PGconn *conn;
        /* socket for the database connection */
        int s;
        /* simple select statement to send over the socket */
        unsigned char stmt[] = "Q\0\0\0\030select * from amaaa";
        /* buffer for the server response */
        unsigned char buf[BUFSIZE];
        ssize_t len, i;
    
        /* connect to the database */
        conn = PQconnectdb("");
        if (conn == NULL)
        {
            fprintf(stderr, "Out of memory connecting to PostgreSQL.\n");
            return 1;
        }
        if (PQstatus(conn) != CONNECTION_OK)
        {
            fprintf(stderr, "%s\n", PQerrorMessage(conn));
            PQfinish(conn);
            return 1;
        }
    
        /* get the TCP socket that corresponds to the connection */
        if ((s = PQsocket(conn)) <= 0)
        {
            fprintf(stderr, "Connection is not open.\n");
            PQfinish(conn);
            return 1;
        }
    
        /* send the simple select statement */
        if (-1 == send(s, stmt, sizeof(stmt), 0))
        {
            perror("Error in send(2)");
            PQfinish(conn);
            return 1;
        }
    
        /*
         * The following is oversimplified.
         * In reality, you'd have to call recv(2) until you have
         * the complete response.
         * But I don't want to bother with analyzing the response
         * and hope that it comes in a single packet.
         */
    
        /* receive the response */
        if (-1 == (len = recv(s, buf, BUFSIZE, MSG_WAITALL)))
        {
            perror("Error in recv(2)");
            PQfinish(conn);
            return 1;
        }
    
        /* print the server response */
        for (i=0; i<len; ++i) {
            if (buf[i] >= ' ' && buf[i] <= 'z')
                printf("%02X(%c) ", buf[i], buf[i]);
            else
                printf("%02X ", buf[i]);
        }
        printf("\n");
    
        /* close the database connection */
        PQfinish(conn);
    
        return 0;
    }