2013-08-25 3 views
1

Linux n00b здесь. Итак, около месяца назад я установил emacs и компилятор gcc/g ++ и начал работать с программированием. Я нашел код в Интернете для программы эхо-сервера, скопировал его и скомпилировал для проверки сетевых функций. Он скомпилирован, но затем, когда я попытался запустить его, я получил сообщение об ошибке: Ошибка сегментации (сбрасывание ядра). Когда я внимательно посмотрел на детали отладчика, это было ошибкой в ​​функции «fwrite()». Я связал код с библиотекой libstdC++. A при компиляции и создании выходного файла, поэтому мне интересно, есть ли какая-то критическая ошибка в фактических библиотечных функциях, и мне нужно вернуться, найти функцию .c sourcecode, а затем добавьте их в заголовки, чтобы они работали. Код размещен ниже. У кого-нибудь еще была эта проблема?Розетки 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

Вот еще некоторые подробности от отладчика: * Segfault произошел с 0x7f6302d53c04 : mov (% rcx),% eax PC (0x7f6302d53c04) OK источник "(% rcx)" не расположен в известном регионе VMA (необходимый читаемый регион!) «% eax» ok * Таким образом, это выглядит как конфликт размера операнда, но где реализована функция fwrite()? Я не написал этот код, как вы. –

+0

@bennofs: Он сказал: «Нет доступных стоп-карт», к сожалению, я не могу. Функция «fwrite()» находится в заголовке в качестве прототипа. Так вот в чем проблема. Но я не знаю, как это исправить. –

ответ

1

Вы не устанавливая buffer переменные-указатели в ваших Writeline() и ReadLine() функций.

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_base или buffer->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

ли вы на самом деле это COPY, или же скопировать биты, а затем вставить его вместе себя?

Это не очень сложно исправить, по крайней мере, до такой степени, что он не разбился сам по себе - я не стал дальше, потому что мои настройки брандмауэра слишком строги, чтобы просто запускать программу и использовать случайный порт; Я не чувствую, что испортил настройку брандмауэра, чтобы проверить ваш код.

Таким образом, как указано 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

Я бы нашел где-то еще, чтобы копировать «отсюда» ... Если это точно, как это получилось, тогда, я бы сказал, это довольно мусор. –

+0

Хорошо, я сделал требуемые изменения, и он все еще разбился .............. СНОВА! В отчете об ошибке упоминается файл ** libc.so.6 **, который не устанавливается должным образом. И дерьмо попало в вентилятор, когда я попытался переместить его в другой каталог. Настолько ясно, что проблема - это файл библиотеки, а не фактический исходный код. Но это для советов. –

Смежные вопросы