2.4.3 创建监听套接字

PostgreSQL允许通过网络(TCP、Bonjour等)或UNIX本地机来访问数据库,本节主要介绍一下如何创建TCP套接字。在介绍创建套接字之前,先介绍以下主要数据结构。

字符串ListenAddresses:该字符串中存储的是服务器的IP地址,如果是多接口主机的话,IP地址之间用“,”隔开,“*”表示所有可用IP接口,缺省值为“localhost”。

整型数组ListenSocket[MAXLISTEN]:该数组用来保存与服务器上某个IP地址(一个服务器可能有多个网卡,因此会设置多个IP地址)绑定的监听套接字描述符,初始时全为-1。MAXLISTEN的值为64。

struct addrinfo结构体:该结构体用来保存我们调用getaddrinfo系统函数返回与协议无关的套接字时需要关心的信息,如要监听的服务器IP地址、服务器端口等相关信息。其结构如数据结构2.4所示。

数据结构2.4 addrinfo

    struct addrinfo  
    {  
    int                ai_flags;            //AI_PASSIVE,AI_CANONNAME  
    intai_family;//地址族协议  
    intai_socktype;//套接口类型  
    intai_protocol;//0或者IPv4、IPv6选项  
    size_tai_addrlen;//套接口地址结构长度  
    struct sockaddr*ai_addr;//套接口地址指针  
    char*ai_canonname;//主机规范名  
    struct addrinfo*ai_next;//指向下一个struct addrinfo的指针  
    };

Postmaster首先调用SplitIdentifierString函数解析字符串ListenAddresses,得到多个服务器IP地址并构成一个List(参见数据结构2.5)。然后取出每一个服务器地址,调用函数StreamServerPort在该地址上创建一个监听套接口,并将返回的套接字描述符保存在整型数组ListenSocket[MAXLISTEN]的第一个值为-1的单元中。

数据结构2.5 Listtypedef

    struct List  
    {  
    NodeTag        type;          //T_List,T_IntList,or T_OidList  
    intlength;//链表长度  
    ListCell*head;//链表的头节点  
    ListCell*tail;//链表的尾节点  

    }List;

List是PostgreSQL中常用的一种链表结构,它的节点类型为ListCell(参见数据结构2.6),在ListCell中可以包含指向任何数据结构的指针。正是因为List和ListCell的独特设计,使得List能够用于建立任何数据类型的链表,在后面的内容中我们还将见到很多使用List的情况。

数据结构2.6 ListCell

    struct ListCell  
    {  
    union                                
    {  
    vOid      *ptr_value;//T_List时指向该节点所对应的数据结构  
    int          int_value;//T_IntList时记录整数值  
    Oid          Oid_value;//T_OidList时记录OID值  
    }data;  
    ListCell  *next;//指向链表中的下一个节点  
    };

StreamServerPort函数在创建监听套接字的时候,首先会填写addrinfo结构体。这里由于创建的是服务器套接字,所以将ai_flags设置为AI_PASSIVE表示该套接字为被动打开,ai_socktype置为SOCK_STREAM表示将要创建的是个字节流的套接口,ai_family将会根据具体情况设置,可以为AF_INET、AF_INET6和AF_UNIX,分别表示IPv4、IPv6和UNIX套接字。完成这些设置之后就可以调用系统函数getaddrinfo来根据服务器地址、服务器端口号对初始addrinfo结构体进行补充,填写其中的套接口地址等关键信息,从而得到一个完整的套接口,最后依次调用socket、bind、listen系统函数就可以创建一个监听套接字了。

socket函数先创建一个socket对象,bind函数则将由getaddrinfo函数补充完整的addrinfo结构体变量和socket对象进行绑定,最后通过listen函数对绑定的套接口进行监听,返回一个监听套接字。处于监听状态的流套接字将维护一个客户端连接请求队列,listen函数的第二个参数设定了该队列最多容纳的客户端连接请求数。如果当一个连接请求到来时,队列已满,那么客户端将收到一个WSAECONNREFUSED错误。

接下来,将调用reset_shared函数创建用于进程间通信的共享内存和信号量,在这之后装载用户认证文件pg_hba.conf和pg_ident.conf,初始化BackendList后台进程双向链表,并创建postmaster.opts文件。

BackendList是一个活动的后台进程表,主要用于跟踪和了解目前有多少子进程,并且在必要的时候给它们发送适当的信号。该进程表主要记录的是由Postmaster通过fork产生的Postgres进程,特殊的子进程例如Startup和BgWriter不在这个表中。

创建监听套接字的代码可参见Postmaster.c文件中的第800~900行。

【责任编辑:云霞 TEL:(010)68476606】

results matching ""

    No results matching ""