PQconnectStartParams, PQconnectStart, PQconnectPoll
功能描述
与数据库服务器建立一个非阻塞的连接。用户应用的执行线程在执行时不会因远端的 I/O 而阻塞。 这个接口的要点是等待 I/O 结束可以发生在应用的主循环里, 而不是在远端(即PQconnectdbParams或PQconnectdb里), 这样应用可以把这件事与其它操作并发起来一起执行。
接口原型
PGconn *PQconnectStartParams(const char * const *keywords,
const char * const *values,
int expand_dbname);
PGconn *PQconnectStart(const char *conninfo);
PostgresPollingStatusType PQconnectPoll(PGconn *conn);
参数说明
PQconnectStartParams中所有参数与PQconnectdbParams中的同名参数意义完全一致。
PQconnectStart中所有参数与PQconnectdb中的同名参数意义完全一致。
返回值
PQconnectStartParams和PQconnectStart均返回连接结构体类型PGconn指针,用于表示一个连接。二者的使用类似。PQconnectPoll返回连接状态,详细内容见其他。
其他
PQconnectStartParams、PQconnectStart 和PQconnectPoll都不会阻塞(进程),不过有一些条件:
1、必须正确提供hostaddr和host参数以确保不会发生正向或者反向的名字查找。
2、如果你调用了PQtrace,确保你跟踪进入的流对象不会阻塞。
3、你必须在调用PQconnectPoll之前确保 socket 处于正确的状态, 像下面描述的那样。
要开始一次非阻塞连接请求,调用conn = PQconnectStart("connection_info_string")
。 若返回空,表明内存不足。 否则,返回一个有效的PGconn指针(尽管还不一定代表一个与数据库有效连接)。进而调用status = PQstatus(conn)
进行检查, 若返回状态为CONNECTION_BAD,PQconnectStart失败。
若PQconnectStart成功,则下一个阶段是轮询libpq, 这样它就可以继续连接序列动作。使用PQsocket(conn) 获取数据库链接下层的套接字描述符。接下来做一个循环:若PQconnectPoll(conn) 的最后一个返回是PGRES_POLLING_READING,那么就等到套接字准备好被读取时,再次调用PQconnectPoll(conn)。反之,若PQconnectPoll(conn) 最后返回PGRES_POLLING_WRITING,那么就等到套接字准备好写时,再次调用PQconnectPoll(conn)。若还没调用PQconnectPoll, 比如,刚刚调用完PQconnectStart,那么按照它刚返回PGRES_POLLING_WRITING的原则行动。继续循环直到PQconnectPoll(conn)返回PGRES_POLLING_FAILED, 表明连接过程失败,或PGRES_POLLING_OK,表明连接成功建立。
在连接的任意时刻,都可以通过调用PQstatus来检查连接的状态。 若返回CONNECTION_BAD状态,则连接失败;若返回CONNECTION_OK, 则连接成功。这两种状态同样也可以从上面的PQconnectPoll的返回值里检测到。其他状态可能(也只能)在一次异步联接过程中发生。这些返回值标识连接过程当前的连接状态, 这些状态可能包括:
标识 | 状态 |
---|---|
CONNECTION_STARTED | 等待进行连接。 |
CONNECTION_MADE | 连接成功;等待发送。 |
CONNECTION_AWAITING_RESPONSE | 等待来自服务器的响应。 |
CONNECTION_AUTH_OK | 已收到认证;等待后端启动结束。 |
CONNECTION_SSL_STARTUP | 协商 SSL 加密。 |
CONNECTION_SETENV | 协商环境驱动的参数设置。 |
在使用PQconnectPoll的时候,连接参数connect_timeout 将被忽略;判断是否超时是应用的责任。否则,后面跟着一个PQconnectPoll 循环的PQconnectStart等效于PQconnectdb。
注意如果PQconnectStart返回一个非空的指针,必须使用完后调用PQfinish,以处理那些结构和所有相关的存储块。尤其在连接尝试失败或放弃时,也必须做此操作。