我想在我的linux项目中异步使用PostgreSQL(9.1)。为此,我必须使用epoll_wait(因为应用程序的其他部分)。目标是最终在边缘触发模式下使用epoll。但即使在非边缘触发模式下,我也无法使连接过程正常工作。我不知道为什么。但是,当用户名和密码正确时,它可以正常工作。但是当密码错误时它也必须工作。在那种情况下,我得到一些我不明白的错误。 : - /这是我使用的代码(连接已经使用PQconnectStart()初始化,参数列表可以正常使用PQconnectdb()):
void ConnectDB(PGconn * connection)
{
int pq_fd = PQsocket(connection);
int epoll_fd = epoll_create1(0);
struct epoll_event event;
struct epoll_event *eventList = (epoll_event *)calloc(64, sizeof(epoll_event));
event.data.fd = pq_fd;
event.events = EPOLLOUT | EPOLLERR;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pq_fd, &event);
while (true) {
PostgresPollingStatusType pt = PQconnectPoll(connection);
switch (pt)
{
case PGRES_POLLING_OK:
printf("*** connection established!\n");
return;
case PGRES_POLLING_FAILED:
printf("*** connection failed: %s\n", PQerrorMessage(connection));
return;
case PGRES_POLLING_ACTIVE:
printf(" --- poll result: PGRES_POLLING_ACTIVE\n");
break;
case PGRES_POLLING_READING:
printf(" --- poll result: PGRES_POLLING_READING - Modifiing epoll to EPOLLIN\n");
event.events = EPOLLIN | EPOLLERR;
if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, PQsocket(connection), &event) == -1) {
printf("epoll_ctl() error: %u: %s\n", errno, strerror(errno));
exit(1);
}
break;
case PGRES_POLLING_WRITING:
printf(" --- poll result: PGRES_POLLING_WRITING - Modifiing epoll to EPOLLOUT\n");
event.events = EPOLLOUT | EPOLLERR;
if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, PQsocket(connection), &event) == -1) {
printf("epoll_ctl() error: %u: %s\n", errno, strerror(errno));
exit(1);
}
break;
}
int n = epoll_wait(epoll_fd, eventList, 64, -1);
if (n == -1) {
printf("epoll_wait() error: %u: %s\n", errno, strerror(errno));
exit(1);
}
}
}
这是我得到的输出:
--- poll result: PGRES_POLLING_WRITING - Modifiing epoll to EPOLLOUT
--- poll result: PGRES_POLLING_READING - Modifiing epoll to EPOLLIN
--- poll result: PGRES_POLLING_READING - Modifiing epoll to EPOLLIN
--- poll result: PGRES_POLLING_READING - Modifiing epoll to EPOLLIN
--- poll result: PGRES_POLLING_WRITING - Modifiing epoll to EPOLLOUT
--- poll result: PGRES_POLLING_READING - Modifiing epoll to EPOLLIN
--- poll result: PGRES_POLLING_READING - Modifiing epoll to EPOLLIN
--- poll result: PGRES_POLLING_WRITING - Modifiing epoll to EPOLLOUT
epoll_ctl() error: 2: No such file or directory
有人有想法吗?
答案 0 :(得分:2)
postgresql客户端库首先尝试ssl-connection,如果失败,则在没有ssl的情况下重试。无论为什么连接失败的原因,这都是完成的,并且它完全没有通知呼叫者。因此,即使错误是错误的密码,客户端库也会关闭文件描述符并重新打开明文的套接字连接。
如果文件描述符已关闭,则会自动从epoll-set中删除 (这会导致您的"没有此类文件或目录"错误消息)。所以你必须手动重新添加它:
if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, PQsocket(connection), &event) == -1) {
if (errno == ENOENT) {
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, PQsocket(connection), &event);
} else {
printf("epoll_ctl() error: %u: %s\n", errno, strerror(errno));
exit(1);
}
}
另一种选择是永久启用或禁用ssl,为此添加sslmode=require
或sslmode=disable
到您的连接字符串。但是,如果您打算使用PGreset()
(或遇到套接字关闭并对调用者透明地重新打开的任何其他情况),那么您将遇到同样的问题。
不可否认,postgresql-client-library的这种行为不是很epoll()
- 友好。在过去,使用select()
或poll()
时,这不是问题,因为内核中没有状态,就像现在使用epoll()
一样。