2015-05-11 23 views
3

我只是通過一些網站學習在Linux socket編程,這裏是使用TCP的我在服務器端代碼中的某些部分:分段錯誤(套接字編程(TCP)在C)

#define BufferLength 100 
#define SERVPORT 3111 
int main() 
{ 
    /* Variable and structure definitions. */ 
    int sd, sd2, rc, length = sizeof(int); 
    int totalcnt = 0, on = 1; 
    char temp; 
    char buffer[BufferLength]; 
    struct sockaddr_in serveraddr; 
    struct sockaddr_in their_addr; 
    fd_set read_fd; 

    /* Get a socket descriptor */ 
    if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    { 
    perror("Server-socket() error"); 
    exit (-1); 
    } 
    else 
    printf("Server-socket() is OK\n"); 

    /* Allow socket descriptor to be reusable */ 
    if((rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0) 
    { 
    perror("Server-setsockopt() error"); 
    close(sd); 
    exit (-1); 
    } 
    else 
    printf("Server-setsockopt() is OK\n"); 

    /* bind to an address */ 
    memset(&serveraddr, 0x00, sizeof(struct sockaddr_in)); 
    serveraddr.sin_family = AF_INET; 
    serveraddr.sin_port = htons(SERVPORT); 
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    printf("Using %s, listening at %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT); 

    /* continue */ 
} 

當我做了最後一行(printf(「使用......」)),我遇到了分段錯誤,爲什麼?謝謝。

+1

你的代碼看起來不錯,它適用於我。在valgrind下運行它不會顯示任何與內存相關的問題,這些問題可以解釋段錯誤。我確實添加了所有必需的標題;我想你的問題可能是由於你錯過了其中的一個或多個。你的編譯器是否發出任何警告? –

+0

約翰,我編譯這個程序時沒有警告。另外,當我運行類似的代碼時,我沒有任何分割錯誤。 – user

+0

@user,我試着在我的Linux上編譯你的一段代碼,它運行時沒有任何分段錯誤。你確定分段錯誤發生在printf嗎? printf之後的代碼是什麼? –

回答

3

的代碼所示偏出#include任何標題,因爲它的立場將不編譯由於一些未定義的符號。

但是,如果您遺漏了只編譯代碼所引用的任何庫函數的原型,則會導致任何函數被假定爲返回int

後一個事實可能是致命的或不是。

在64位系統中的至少是在用作參數來printf()inet_ntoa()的情況下是致命的,因爲在64位的系統上它最有可能預期返回一個64位(char終場)值(但32位int )。因此(假設原型未命中)生成代碼時,編譯器假定inet_ntoa()返回32位int,這將導致「切斷」返回地址的最高有效32位。試圖從printf()這樣的「殘缺」,因此(最有可能)無效的地址引發未定義的行爲,並在你的情況導致觀察到分割違規。

通過添加解決這個問題,添加相關的原型(爲inet_ntoa()):

#include <arpa/inet.h> 

編譯器應該警告你這一點。要啓用gcc的所有編譯器警告,請使用選項-Wall -Wextra -pedantic。認真對待這些警告。

+0

您的解決方案通過包括標題爲我工作,非常感謝! – user

0

inet_ntoa()似乎很可能返回NULL,導致在printf()中取消引用時發生段錯誤。我找不到明確指出Linux版本的inet_ntoa可以實現的直接參考,但是我發現了幾個提出這種說法的人,而且這是代碼中指針被解除引用的唯一一點。

該問題底部的答案:segmentation fault for inet_ntoa聲明inet_ntoa可以返回NULL。但是,根據他的參考鏈接,我找不到這個事實的實際陳述。

有,做狀態明白地INET_NTOA()可以空在這裏返回一個MSDN文章(這是暗示性的,但當然,這並不直接適用於Linux的代碼):https://msdn.microsoft.com/en-us/library/windows/desktop/ms738564%28v=vs.85%29.aspx

+1

很難相信它會返回NULL INADDR_ANY。很難相信,首先存在一個32位參數值可能出現的錯誤。 – EJP

+0

有點贊同你的第一點,但沒有很多其他候選人在那裏的段錯誤,這導致我作爲唯一可能的候選人,即使不太可能。至於32位參數的錯誤,是不是有相當多的值不會轉換爲有效的32位IP地址? –