2012-07-31 75 views
4

我在Linux下的服務器套接字有問題。出於某種原因,我不知道服務器套接字消失,並且在等待輸入連接的select調用中出現Bad file descriptor錯誤。當我在不同的線程中關閉不相關的套接字連接時,總是會出現此問題。這發生在2.6.36內核的嵌入式Linux上。Linux服務器套接字 - 錯誤的文件描述符

有誰知道爲什麼會發生這種情況?服務器插座是否可以簡單地消失導致Bad file descriptor是否正常?

編輯: 其他套接字代碼實現了一個VNC服務器,並運行在一個完全不同的線程中。在其他代碼中唯一特別的是使用setjmp/longjmp,但這應該不成問題。

是創建服務器套接字的代碼如下:

int server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 

struct sockaddr_in saddr; 
memset(&saddr, 0, sizeof(saddr)); 
saddr.sin_family = AF_INET; 
saddr.sin_addr.s_addr = htonl(INADDR_ANY); 
saddr.sin_port = htons(1234); 

const int optionval = 1; 
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &optionval, sizeof(optionval)); 

if (bind(server_socket, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { 
    perror("bind"); 
    return 0; 
} 

if (listen(server_socket, 1) < 0) { 
    perror("listen"); 
    return 0; 
} 

我等待進來的連接使用下面的代碼:

static int WaitForConnection(int server_socket, struct timeval *timeout) 
{ 
    fd_set read_fds; 

    FD_ZERO(&read_fds); 
    int max_sd = server_socket; 
    FD_SET(server_socket, &read_fds); 

    // This select will result in 'EBADFD' in the error case. 
    // Even though the server socket was not closed with 'close'. 
    int res = select(max_sd + 1, &read_fds, NULL, NULL, timeout); 
    if (res > 0) { 
     struct sockaddr_in caddr; 
     socklen_t clen = sizeof(caddr); 
     return accept(server_socket, (struct sockaddr *) &caddr, &clen); 
    } 

    return -1; 
} 

編輯: 當問題的情況下發生我目前只是重新啓動服務器,但我不明白爲什麼服務器套接字ID應該突然變成無效的文件描述符:

int error = 0; 
socklen_t len = sizeof (error); 
int retval = getsockopt (server_socket, SOL_SOCKET, SO_ERROR, &error, &len); 
if (retval < 0) { 
    close(server_socket); 
    goto server_start; 
} 
+2

沒有什麼錯,你發佈的代碼,誤差必須在其他地方。例如,關閉它之後是否使用了套接字? – 2012-07-31 07:22:14

+0

準確使用的線程在哪裏? – 2012-07-31 07:32:10

+0

上面的代碼在一個線程中運行。另一個代碼在另一個也運行線程的模塊中。關閉連接將殺死服務器。我沒有想過如果我沒有關閉服務器套接字就會失效。 – trenki 2012-07-31 07:42:46

回答

-3

在Linux中,一旦你創建了一個連接並且它被關閉了,那麼你必須等待一段時間才能建立新的連接。 與Linux一樣,套接字不釋放端口號。只要你關閉了插座。

OR

你重用插座,再不濟的文件描述符要來了。

+0

它不是保留的IP地址(這將是嚴重的),但端口號 – 2012-07-31 08:09:47

+0

@JensGustedt是其端口號。 – 2012-07-31 08:24:19

+0

這隻有在以下情況下才成立:(a)您創建的客戶端連接不在此處發生,(b)您綁定到特定的出站端口號,不需要這樣做,哪些也不會發生在這裏,和(三)你是結束開始關閉。 -1完全和完全不相關。 – EJP 2014-07-25 23:34:27

1

您不區分代碼中的兩個錯誤情況,兩者都可能失敗selectaccept。我的猜測是,你只是有一個時間,並選擇返回0

  • 打印retvalerrnoelse分支
  • 調查accept返回值seperately
  • 確保errno重置爲0每個系統的前調用
4

插座(文件描述符)通常遭受與C中的原始指針相同的管理問題。當你關閉套接字,不要忘記分配-1,這樣就保持了描述值的變量:

close(socket); 
socket = -1; 

正如你會做C指針

free(buffer); 
buffer = NULL; 

如果你忘記這樣做喲能後來關閉套接字兩次,如果它是一個指針,你會兩次訪問內存兩次。

另一個問題可能涉及到一個事實,即人們通常忘記:在UNIX環境文件描述符從0開始。如果在某個地方的代碼你有

struct FooData { 
    int foo; 
    int socket; 
    ... 
} 

// Either 
FooData my_data_1 = {0}; 
// Or 
FooData my_data_2; 
memset(&my_data_2, 0, sizeof(my_data_2)); 

在這兩種情況下my_data_1my_data_2有一個有效的描述符(socket)值。後來,一些代碼,負責釋放FooData結構可能會盲目close()這個描述符,這恰好是你服務器的偵聽套接字(0)。

+0

謝謝!你的提示確實幫助我找到了一個邪惡的錯誤。 – jkow 2017-03-30 16:01:23

+0

@jkow我很高興這是有幫助的。別客氣。 – GreenScape 2017-03-30 17:57:30

0

1-閉上你的插座:

close(sockfd); 

2-清楚你的套接字文件從選擇一套描述:

FD_CLR(sockfd,&master); //opposite of FD_SET 
相關問題