2016-02-03 87 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