2013-08-25 40 views
1

Linux n00b這裏。大約一個月前,我安裝了emacs和gcc/g ++編譯器,並開始編程。我在網上找到了一些echo服務器程序的代碼,將它複製並編譯成測試網絡功能。它編譯,但後來當我試圖運行它,我得到了錯誤信息:分段錯誤(核心轉儲)。當我仔細查看調試器的詳細信息時,這是「fwrite()」函數中的錯誤。我在編譯和創建輸出文件時將代碼鏈接到了庫文件libstdC++。a,因此它確實讓我懷疑實際庫函數中是否存在某些嚴重錯誤,並且需要返回找到.c源代碼函數,然後將它們添加到標題以使其工作。該代碼發佈如下。任何人都有這個問題?Linux套接字:分割錯誤

#include <sys-socket.h>  /* socket definitions  */ 
#include <sys-types.h>  /* socket types    */ 
#include <netinet-in.h>  /* inet (3) functions   */ 
#include <unistd.h>   /* misc. UNIX functions  */ 
#include <stdlib.h> 
#include <stdio.h> 
#include <errno.h> 
#include <ether.h> 
#include <string.h> 


/* Global constants */ 

#define ECHO_PORT   2002 
#define MAX_LINE   1000 
#define LISTENQ   5 


ssize_t Readline(int sockd, char *vptr,size_t maxlen) { 
    ssize_t n, rc; 
    char* c; 
    msghdr* buffer; 

    buffer->msg_iov->iov_base = vptr; 
    buffer->msg_iov->iov_len = maxlen; 

    for (n = 1; n < maxlen; n++) { 

     if ((rc = recvmsg(sockd,buffer, 1)) == 1) { 
    c = buffer->msg_iov->iov_base++; 
     if (*c == '\n') 
     break; 
    } 
    else if (rc == 0) { 
     if (n == 1) 
     return 0; 
     else 
     break; 
    } 
    else { 
     if (rc < 0) 
     continue; 
     return -1; 
    } 
    } 

    buffer->msg_iov->iov_base = 0; 
    return n; 
} 


/* Write a line to a socket */ 

ssize_t Writeline(int sockd, char *vptr) { 
    msghdr  *buffer; 


    buffer->msg_iov->iov_base = vptr; 
    size_t  nleft = buffer->msg_iov->iov_len; 
    ssize_t  nwritten; 

    while (nleft > 0) { 
    if ((nwritten = sendmsg(sockd, buffer, nleft)) < 0) { 
      return -1; 
    } 
    nleft -= nwritten; 
    buffer += nwritten; 
    } 

    return nwritten; 
} 

int main(int argc, char *argv[]) { 
    int  list_s;    /* listening socket   */ 
    int  conn_s;    /* connection socket   */ 
    short int port;     /* port number    */ 
    struct sockaddr_in servaddr; /* socket address structure */ 
    char  *endptr;    /* for strtol()    */ 
    char  buffer[MAX_LINE]; 




    port = 5000; 


    /* Create the listening socket */ 

    if ((list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 
    fprintf(stderr, "ECHOSERV: Error creating listening socket.\n"); 
    exit(EXIT_FAILURE); 
    } 


    /* Set all bytes in socket address structure to 
     zero, and fill in the relevant data members */ 

    memset(&servaddr, 0, sizeof(servaddr)); 
    servaddr.sin_family  = AF_INET; 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servaddr.sin_port  = htons(port); 


    /* Bind our socket addresss to the 
    listening socket, and call listen() */ 

    if (bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { 
    fprintf(stderr, "ECHOSERV: Error calling bind()\n"); 
    exit(EXIT_FAILURE); 
    } 

    if (listen(list_s, LISTENQ) < 0) { 
    fprintf(stderr, "ECHOSERV: Error calling listen()\n"); 
    exit(EXIT_FAILURE); 
    } 


    /* Enter an infinite loop to respond 
     to client requests and echo input */ 

    while (1) { 

    /* Wait for a connection, then accept() it */ 

    if ((conn_s = accept(list_s, NULL, NULL)) < 0) { 
     fprintf(stderr, "ECHOSERV: Error calling accept()\n"); 
     exit(EXIT_FAILURE); 
    } 


    /* Retrieve an input line from the connected socket 
     then simply write it back to the same socket.  */ 

    Readline(conn_s, buffer, MAX_LINE-1); 
    Writeline(conn_s, buffer); 


    /* Close the connected socket */ 

    if (shutdown(conn_s,0) < 0) { 
     fprintf(stderr, "ECHOSERV: Error calling close()\n"); 
     exit(EXIT_FAILURE); 
    } 
    } 
} 
+0

你可以發佈完整的堆棧跟蹤嗎? – bennofs

+0

以下是來自調試器的更多詳細信息:*段錯誤發生在0x7f6302d53c04 :mov(%rcx),%eax PC(0x7f6302d53c04)OK源(「%rcx)」未位於已知VMA區域(需要可讀區域! 「%eax」ok *所以這看起來像是操作數大小衝突,但fwrite()函數在哪裏實現?我沒有寫這個代碼來介意你。 –

+0

@bennofs:它說「沒有stacktrace可用」,所以不幸我不能。函數「fwrite()」作爲原型在標題中。所以這似乎是問題所在。但我不知道如何解決它。 –

回答

1

你是不是在你的Writeline()ReadLine()功能設置buffer指針變量。

ssize_t Writeline(int sockd, char *vptr) { 
    msghdr  *buffer; 

    //this is not appropriate as buffer does not point to appropriate memory. 
    buffer->msg_iov->iov_base = vptr; 

    size_t  nleft = buffer->msg_iov->iov_len; 
    ssize_t  nwritten; 
    ...  
    return nwritten; 
} 

訪問buffer->msg_iov->iov_basebuffer->msg_iov->iov_len甚至buffer也不是沒有分配,或設置適當的內存相應無效。

+0

因此,我重新安裝了linux(以及emacs,gcC++和庫),它工作!我知道有一個比源代碼更大的問題。我的很多其他頭文件無法正常工作,因此可能以前的重新安裝(在嘗試調整網絡設置導致啓動錯誤後)必須破壞這些文件。 –

4
ssize_t Writeline(int sockd, char *vptr) { 
    msghdr  *buffer; 


    buffer->msg_iov->iov_base = vptr; 

您的指針緩衝區未初始化。你可以看看這個代碼片斷正確地做到這一點:

 /* This structure contains parameter information for sendmsg. */ 
    struct msghdr mh; 

     /* The message header contains parameters for sendmsg. */ 
    mh.msg_name = (caddr_t) &dest; 
    mh.msg_namelen = sizeof(dest); 
    mh.msg_iov = iov; 
    mh.msg_iovlen = 3; 
    mh.msg_accrights = NULL;   /* irrelevant to AF_INET */ 
    mh.msg_accrightslen = 0;   /* irrelevant to AF_INET */ 

    rc = sendmsg(s, &mh, 0);   /* no flags used   */ 
    if (rc == -1) { 
     perror("sendmsg failed"); 
     return -1; 
    } 
    return 0; 
} 

sendmsg

1

你真的複製此,還是你複製位,然後將其粘貼到自己一起?

要解決它至少不會自己崩潰的問題並不難 - 我沒有進一步探討,因爲我的防火牆設置太嚴格,無法啓動程序並使用隨機端口,並且我不想搞亂我的防火牆設置來測試你的代碼。

所以,正如msghdr *buffer;指出的那樣意味着buffer的指針未初始化。簡單的解決方法是不使用指針,而在需要時使用buffer的地址。然後您需要有一個iov數據結構。

所以,在接收,你最終是這樣的:

msghdr buffer; 
iovec iov; 

buffer.msg_iov = &iov; 
... 
if ((rc = recvmsg(sockd, &buffer, 1)) == 1) { 
    c = vptr++; 
    buffer.msg_iov->iov_base = vptr; 

注意&在緩衝區的前面。我還更改了下一行,因爲它是在void指針上執行++,這在C++中沒有明確定義,所以編譯器發出警告。 (還有一個對buffer未初始化的警告)。

`WriteLine函數需要類似的處理。

iovec iov; 

buffer.msg_iov = &iov; 
buffer.msg_iov->iov_base = vptr; 
size_t  nleft = MAX_LINE; 

... 
    if ((nwritten = sendmsg(sockd, &buffer, nleft)) < 0) { 
    .... 

    nleft -= nwritten; 
    vptr += nwritten; 
    buffer.msg_iov->iov_base = vptr; 

再次,iov_base的增量遞增void *,其中,因爲我寫上面還沒有定義,因此需要確保該指針有不同的類型 - 重用vptr是體面這裏。

另外,我將nleft更改爲MAX_LINE,因爲您不傳遞行的大小。我建議你改變它,以便它將大小作爲參數,類似於ReadLine函數。

最後,請在編譯代碼時自己動手,並使用-Wall -Werror - 這意味着當您執行「愚蠢」操作時會收到警告 - 它可能有效,但也可能無效。幾乎所有來自編譯器的警告都是有用的。

請記住,在C或C++中使用指針時,應確保它指向某處。只寫T* ptr;只給你一個指針,沒有附加到指針的內存,所以在你使用那個指針之前,你應該以某種方式分配它。

我很不相信這涵蓋了一切 - 但它應該讓你在某種程度上得到一些工作。

+0

馬特,我複製粘貼它。 –

+1

我會找到其他地方複製'n'paste ...如果這正是它是如何來的,那麼它是非常垃圾的,我會說。 –

+0

好的,我做了所需的更改,但仍然崩潰..............再次!錯誤報告提到文件** libc.so.6 **沒有正確安裝。當我試圖將它重新定位到不同的目錄時,狗屎擊中了粉絲。所以顯然問題是庫文件,而不是實際的源代碼。但這是提示。 –