Ошибка сегментации - Программирование сокетов - C - PullRequest
0 голосов
/ 05 июня 2018

Я пытаюсь написать модель эхо-сервера \ клиента на языке C. Мой код компилируется, но выдает ошибку ошибки сегментации во время выполнения [я считаю, что на стороне сервера].При тестировании в среде отладки CLion серверный процесс может выполнить системный вызов accept () и войти в состояние ожидания, пока клиент не подключится.Поэтому я считаю, что ошибка сбоя сегментации происходит после того, как клиент совершил системный вызов connect ().

Вот соответствующие фрагменты кода (только последняя часть - не полная программа):

/* [6] LISTEN FOR CONNECTIONS ON BOUND SOCKET===================================================================== */
struct sockaddr_storage ample;    /* from Beej Guide 5.6 accept() */
socklen_t ample_sz = sizeof(ample);
fd_activeSock = accept(fd_listenSock, (struct sockaddr *)&established_SERV_param, &ample_sz);

if (fd_activeSock == -1)    /* Error checking */
{
    fprintf(stderr, "\nNo forum for communication...\nTERMINATING PROCESS");
    exit(EXIT_FAILURE);
}

printf("\nCommunication Established! What's your sign??");
freeaddrinfo(established_SERV_param);    /* free up memory */

/* [7] ACCEPT A CONNECTION (BLOCKING)============================================================================= */

/* MAIN LOOP====================================================================================================== */
while(1)
{
    bzero(msg_incoming, 16);
    recv(fd_activeSock, msg_incoming, 16, 0);
    printf("%s", msg_incoming);
    send(fd_activeSock, msg_incoming, 16, 0);
}

Когда я запускаю обе программы в отдельных терминалах (сначала сервер обрабатывает, конечно),последний оператор печати, который выполняется перед ошибкой:

printf("\nCommunication Established! What's your sign??");

Ошибка выводится на серверный терминал.Есть дамп ядра;для будущих проблем, может кто-нибудь предложить учебник для начинающих по прочесыванию файлов дампа ядра.Кроме того, я запустил код с закомментированным вызовом freeaddrinfo () и все еще получаю ошибку ошибки сегментации, поэтому я не верю, что это проблема.Зачем вообще его запускать?Я не хочу утечки памяти.Спасибо за вашу помощь.

Ответы [ 2 ]

0 голосов
/ 05 июня 2018
freeaddrinfo(established_SERV_param)

Должен вызываться, когда established_SERV_param получено с помощью getaddrinfo.Здесь established_SERV_param, вероятно, является переменной стека.Следовательно, вы пытаетесь освободить указатель на переменную стека.

Ух, что-то не так в вашей программе.Так как freeaddrinfo ожидает указатель, но это переменная, так как вы используете & при вызове accept.Удаление звонка на freeaddrinfo может исправить его.

Если вышеприведенного недостаточно, важно увидеть, как msg_incoming определяется / выделяется.Он не должен быть массивом const или инициализирован строковым литералом, делающим его const.Если это указатель, он должен быть адекватно распределен в памяти, используя malloc.

Анализ дампа ядра:

Скомпилируйте ваш код с включенной отладкой и выключенной оптимизацией

gcc -g -O0

Затем откройте файл ядра в gdb как

gdb <executable> <core file>
(gdb) bt 

Выше, bt покажет вам обратную трассировку, в которой произошел сбой программы.Вы можете перейти к функции, вызвавшей сбой, командой fr 0 и вывести некоторые переменные.Учебник для GDB можно найти здесь

0 голосов
/ 05 июня 2018

recv () явно не помещает нулевой терминатор в конец буфера, но printf() ожидает его.

В выражениях:

bzero(msg_incoming, 16);
recv(fd_activeSock, msg_incoming, 16, 0);
printf("%s", msg_incoming); 

Хотя msg_incoming обнулен, когда он заполняется в вызове recv, если заполнены все 16 элементов, нет гарантии, чтопоследний элемент массива был заполнен символом '\ 0', оставляя буфер как массив с ненулевым символом в конце.Если это произойдет, то при вызове printf() возможна ошибка.Или, что еще хуже, ошибка может не произойти , что заставляет вас думать, что ваш код работает нормально.(AKA неопределенное поведение)

Исправлена ​​проблема с проверкой возвращаемого значения recv () :

ssize_t bytes = recv(fd_activeSock, msg_incoming, 16, 0);
if(bytes <= 0)
{
    //handle error/end of message condition
}
else
{
    msg_incoming[bytes] = '\0';
    printf("%s", msg_incoming);
}

Дополнительные материалы на Чтение данных с сокета .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...