Почему я получаю ошибку сегментации в моей программе сервера C (но только иногда)?

Прямо сейчас я пытаюсь написать простое клиент-серверное приложение, чтобы измерить время прохождения туда и обратно в локальной сети для TCP-сообщений различных размеров (я делаю синхронизацию на стороне клиента). Программа отлично работает для пакетов небольшого размера (> 1000 байт), но я получаю ошибку сегментации: ошибка 11 для входных данных большей величины (10 КБ или больше).

int main() 
{ 
    struct sockaddr_in sin; 
    char buf[MAX_LINE]; 
    int len; 
    int s, new_s; 
    /* build address data structure */ 
    bzero((char *)& sin, sizeof( sin)); 
    sin.sin_family = AF_INET; 
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons( SERVER_PORT);
    /* setup passive open */ 
    if (( s = socket( PF_INET, SOCK_STREAM, 0)) < 0) { 
        perror("tcp program: socket"); 
        exit(1); 
    } 
    if (( bind(s, (struct sockaddr *)& sin, sizeof(sin))) < 0) { 
         perror("tcp program: bind"); 
         exit( 1); 
 } 
    listen(s, MAX_PENDING); 
    /* wait for connection, then receive and print text */
     while(1) { 
        socklen_t lent = (unsigned int)&len;
        if ((new_s = accept(s, (struct sockaddr *)& sin, &lent)) < 0) { 
            perror("tcp program: accept"); 
            exit( 1); 
        }


        while ((len = recv(new_s, buf, sizeof(buf), 0))){ 
            char msg[len];
            send( new_s, msg, len, 0); //echo message of same length as received message
        }
        close(new_s); 
      }      
}

Опять же, целью было измерить RTT, поэтому я хотел, чтобы клиент отправлял сообщение, указанный выше сервер получал его, а затем отправлял обратно сообщение эквивалентного размера. Я также хотел, чтобы сервер продолжал вращаться, чтобы клиент мог работать итеративно, отправляя сообщения размером 1 КБ, 10 КБ,... 1000 КБ и т. д. Однако такие итерации обычно приводят к ошибке сегментации.

Как ни странно, если я настрою свой клиент для запуска, например, отправки одного сообщения размером 12 КБ, сервер работает нормально и продолжает работать. И если я подожду пару секунд, я могу даже несколько раз вызвать своего клиента, и сервер не отстанет. Но если я запускаю отправку одного сообщения в быстрой последовательности, я снова получаю segfault.

Любые идеи? Заранее извиняюсь за любые элементарные ошибки в стиле или формате. Это мой первый настоящий набег на язык C помимо «hello world».

Спасибо!


person Tom Kreamer    schedule 17.11.2014    source источник
comment
См. этот stackoverflow.com/questions/12552968/   -  person Arun Gupta    schedule 17.11.2014
comment
Большое спасибо, Мером! Это фактически обеспечило точное решение проблемы: локальное объявление char *msg привело к нехватке памяти для выделения возвращаемого сообщения. Объявление массива за пределами цикла исправило это. Если бы я мог отдать вам должное за ответ, я бы это сделал!   -  person Tom Kreamer    schedule 17.11.2014


Ответы (1)


Я не знаю, единственная ли это часть кода, которая неверна, но это неправильно:

while ((len = recv(new_s, buf, sizeof(buf), 0)))

Пожалуйста, прочтите справочную страницу, в частности, для recv() (выделение добавлено)...

Эти вызовы возвращают количество полученных байтов, или -1, если произошла ошибка. Возвращаемое значение будет равно 0, когда одноранговый узел выполнит корректное завершение работы.

Мы знаем, что сети ненадежны, и recv() и его друзья довольно часто возвращают ошибки.

Кроме того, массивы переменной длины в C представляют собой довольно опасную конструкцию, поскольку они выполняют динамическое размещение в стеке. По сути, они alloca() замаскированы, и мы знаем, насколько alloca() опасны. Итак, этот бит:

char msg[len]; // serious problems unless we have good bounds for len
person Dietrich Epp    schedule 17.11.2014
comment
Спасибо за отзыв, Дитрих Эпп: То, что вы сказали о возвращаемом значении recv(), имеет смысл, поэтому я соответствующим образом модифицировал свой цикл. К счастью, границы len довольно хорошо определены моей клиентской программой, поэтому я должен подготовиться соответствующим образом. - person Tom Kreamer; 17.11.2014