2016-08-24 49 views
-1

我在套接字選擇上返回-1。但是,只有在我們使用新安裝的sybase數據庫時纔會發生這種情況。對舊數據庫使用此代碼,我沒有得到任何套接字選擇錯誤,一切正常。C在Solaris上的套接字選擇錯誤

在下面的例子HOW_MANY = 2,和timeout_secs = 60

需要注意的是在工作時只要file_limits.rlim_cur下面的代碼爲256。然而,隨着新的數據庫file_limits.rlim_cur = 65,000和套接字選擇返回-1。我試圖將select中的第一個參數硬編碼爲256,但它仍然返回-1。

int socket_activity(int how_many, int *fd, int timeout_secs) 
{ 
int         i; 
int         select_fd; 
fd_set        read_fds; 
fd_set        except_fds; 
struct timeval    timeout; 
struct rlimit    file_limits; 

/* 
** Determine the current limits. 
*/ 

if (getrlimit(RLIMIT_NOFILE, &file_limits) != 0) 
    return(-1); 

/* 
** Set up the select structures. Initialize the timeout to the specified 
** seconds. Only non-negative file descriptors are initialized. 
*/ 

FD_ZERO(&read_fds); 
FD_ZERO(&except_fds); 
for (i = 0; i < how_many; i++) 

    if (fd[i] >= 0) { 

     FD_SET(fd[i], &read_fds); 
     FD_SET(fd[i], &except_fds); 

    } /* of if */ 

timeout.tv_sec = timeout_secs; 
timeout.tv_usec = 0; 

/* 
** Perform the select and check on the results. 
*/ 

select_fd = select(file_limits.rlim_cur, 
        &read_fds, 
        NULL, 
        &except_fds, 
        &timeout); 

if (select_fd > 0) { 

    /* 
    ** Scan the list of file descriptors and return which file 
    ** descripitor show activity. Only check non-negative file descriptors. 
    */ 

    for (i = 0; i < how_many; i++) 
     if ((fd[i] >= 0) && 
      (FD_ISSET(fd[i], &read_fds))) 
      return(fd[i]); 

    /* 
    ** No file descriptor showed activity so return zero to indicate 
    ** that a timeout occured. 
    */ 

    return(0); 

} /* of if */ 

else 

    /* 
    ** Simply return the return value from select (the function will 
    ** return a 0 on timeout or a -1 on error). 
    */ 

    return(select_fd); 

} /* of function */ 
+0

我假設你的'for'循環應該有一些括號嗎? – yano

+1

如果'select'返回-1,你應該調用'perror'來找出失敗的原因。 – dbush

+0

可能你已經超過了'FD_SETSIZE'?請參閱http://stackoverflow.com/questions/7976388/increasing-limit-of-fd-setsize-and-select –

回答

0

您真的需要post an MCVE才能獲得真正的幫助。這是更多的猜測,而不是真正的答案。

首先,假設你要傳遞的int *一個指向int陣列打開的文件描述符,這是沒用的:

/* 
** Determine the current limits. 
*/ 

if (getrlimit(RLIMIT_NOFILE, &file_limits) != 0) 
    return(-1); 

如果你要通過已經打開文件描述符,該對開放描述符數量的資源限制是完全不相關的 - 描述符已經打開,並且如果出現了某種情況,則可能無法對某些描述符采取行動。

其次,如果打開文件的限制大於FD_SETSIZE中的值,則這是有問題的。你通過數組來選擇 - read_fdsexcept_fds - 每個至多有FD_SETSIZE元素:

select_fd = select(file_limits.rlim_cur, 
        &read_fds, 
        NULL, 
        &except_fds, 
        &timeout); 

我不知道是什麼FD_SETSIZE上安裝Solaris,但低於你的貼「的代碼給它工作時file_limits.rlim_cur256「的問題,我強烈懷疑這就是發生了什麼。鑑於Solaris select(3C) man page的內容

錯誤

select()pselect()功能將失敗:

...

EINVALnfds參數小於0或更大比FD_SETSIZE

您需要修復您的代碼。

而這個數組中後面的會導致描述符的飢餓:

for (i = 0; i < how_many; i++) 
    if ((fd[i] >= 0) && 
     (FD_ISSET(fd[i], &read_fds))) 
     return(fd[i]); 

你總是返回與活動的第一個描述符,你找到。如果陣列中的第一個總是繁忙,那麼它將是唯一一個得到服務的人。

你也忽略了except_fds。如果其中一個「變壞」,那麼其他描述符將不會有可讀的數據,否則您的代碼將停止執​​行除了在select()中循環以外的任何操作。

+0

謝謝你,改變nfds參數解決了我的問題。抱歉沒有發佈MCVE。我試圖修復我從未見過的20年前的代碼,但不知道如何去做。 –