2016-02-03 60 views
1

我希望在我的linux项目中异步使用PostgreSQL(9.1)。为此,我必须使用epoll_wait(因为应用程序的其他部分)。目标是最终在边缘触发模式下使用epoll。但是我无法使连接过程起作用,即使在非边缘触发模式下也是如此。我不知道为什么。但是,当用户名和密码正确时,它就可以工作。但是,当密码错误时,它也必须工作。在这种情况下,我收到了一些我不明白的错误。 : - /这是我使用(连接已经用完PQconnectStart(),并与PQconnectdb里正常工作的参数列表()初始化)代码:PostgreSQL与epoll_wait异步连接

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

postgresql客户端库首先尝试一个ssl连接,如果失败,它将在没有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=requiresslmode=disable您为这个连接字符串。但是,如果您打算使用PGreset()(或遇到任何其他情况,即套接字已关闭并且对调用者透明地重新打开),那么您将遇到同样的问题。

不可否认,postgresql-client-library的这种行为并不是非常友好的epoll()。在过去,当使用select()poll()时,这是一个没有问题的问题,因为现在内核中没有像epoll()那样的状态。

+0

这有帮助 - 非常感谢! – SchodMC