Напоминаю про задавание вопросов.

92 views
Skip to first unread message

Коренберг Марк

unread,
Oct 7, 2011, 10:52:09 AM10/7/11
to usu_netprog
Товарищи студенты! не стесняемся задавать вопросы. пожалуйста пишите,
и будут вам ответы.

Anton Fedorov

unread,
Oct 8, 2011, 12:01:33 AM10/8/11
to usu_netprog
Что такое ошибка сегментирования, в каких случаях она возникает и как
этого избежать?

Вот код не вызывающий ошибку сегментирования:
https://docs.google.com/leaf?id=0B9wfqavDettQYTJiZGRhOWUtOWE0NS00ZmI1LTk4YTAtMjMxMzA5NTExZjNj&hl=ru

А вот этот же код с минимальными изменениями почему-то вызывает:
https://docs.google.com/leaf?id=0B9wfqavDettQNTgyYzIyNjctYzZmZi00Y2ZlLWI3NDUtNDBlOGM4ZDk5OWQ1&hl=ru
( переставлены местами
char *buffer, *str;
и
int counter = 0;
)

В чем дело?

Message has been deleted

Alexander E. Patrakov

unread,
Oct 8, 2011, 9:40:08 AM10/8/11
to usu_n...@googlegroups.com
08.10.2011 10:01, Anton Fedorov пишет:

> Что такое ошибка сегментирования, в каких случаях она возникает и как
> этого избежать?

Ошибка сегментирования возникает, когда программа обращается к памяти,
которая ей не принадлежит.

> Вот код не вызывающий ошибку сегментирования:
> https://docs.google.com/leaf?id=0B9wfqavDettQYTJiZGRhOWUtOWE0NS00ZmI1LTk4YTAtMjMxMzA5NTExZjNj&hl=ru

Это тебе повезло (он должен вызывать такую ошибку). У тебя переменная
buffer не инициализируется перед передачей в sprintf(). Поэтому в момент
вызова sprintf() этот указатель указывает на какую-то случайную область
памяти. Переменную надо либо переобъявить так:

char buffer[много];

либо инициализировать путем присвоения ей того, что вернет malloc() и не
забывать в конце эту память освобождать с помощью free(). И чтобы буфер
не переполнялся, использовать snprintf.

Такие ошибки (неинициализированная переменная, выход за границу буфера)
хорошо отлавливает valgrind.

gcc -Wall --pedantic -g3 main.c
valgrind --leak-check=full --show-reachable=yes ./a.out

--
Александр Патраков

M.Muzafarov

unread,
Oct 16, 2011, 6:49:21 AM10/16/11
to usu_netprog
Что нужно обрабатывать, чтобы сервер работал постоянно?

Несмотря на все while(1), при отключении клиента сервер завершает свою
работу.
То есть интересует вопрос последовательной обработки многих клиентов,
вместо одного.

Message has been deleted

Alexander E. Patrakov

unread,
Oct 16, 2011, 8:21:30 AM10/16/11
to usu_n...@googlegroups.com
16.10.2011 16:49, M.Muzafarov пишет:

Надо понять, что вообще происходит (сигнал? крах?). Для этого можно
запустить сервер под strace.

--
Александр Патраков

Марк Коренберг

unread,
Oct 16, 2011, 1:21:23 PM10/16/11
to usu_n...@googlegroups.com
16 октября 2011 г. 16:49 пользователь M.Muzafarov
<m.muz...@gmail.com> написал:
А нельзя ли заполучить исходники? :)


--
Segmentation fault

M.Muzafarov

unread,
Oct 17, 2011, 11:50:17 AM10/17/11
to usu_netprog
РЕШЕНО. Происходил SIGPIPE невозможности отправить ответ, после чего
процесс самоубивался. Решено добавлением проверки на пустоту сообщения
от клиента (если получено 0 байт - клиент отключился).
if ((bytes_recieved = recv(connected,recv_data,1024,0))==0) break;

Alexander E. Patrakov

unread,
Oct 17, 2011, 11:58:27 AM10/17/11
to usu_n...@googlegroups.com, M.Muzafarov
17.10.2011 21:50, M.Muzafarov пишет:
SIGPIPE по идее можно предотвратить с помощью передачи MSG_NOSIGNAL
функциям send() и recv(). Проверку значения, возвращаемого recv(), это
не отменяет.

P.S. проверь, не утекают ли у тебя файловые дескрипторы. По хорошему,
если recv() вернул 0 или -1 с "невменяемой" ошибкой (т.е. не EAGAIN и не
EINTR), надо вызвать close().

--
Александр Патраков

Коренберг Марк

unread,
Oct 17, 2011, 12:33:10 PM10/17/11
to usu_netprog

Обычно в таких if проверяют == -1, но если на 0 реакция та же, то
можно if ( ... <= 0)

Кстати, если клиент КОРРЕКТНО отключился (TCP FIN), то:
recv может после этого получить часть данных которые клиент успел
послать,
последующие recv вернут 0.
Если продолжать делать recv() то код возврата не предсказуем (0 или
-1)
send же тоже может послать часть данных, а последующий send вернёт
(ECONNRESET или EPIPE)

Если разрыв соединения произошёл внезапно (TCP RST) (например, клиент
сам не закрыл дескриптор, в клиенте произошла ошибка, процесс был убит
и т.д.) то
recv может после этого получить часть данных которые клиент успел
послать,
последующие recv вернут -1 (ECONNRESET, EPIPE, ECONNABORTED)
send() Тоже может вернуть часть данных, после чего вернёт (ECONNRESET,
EPIPE, ECONNABORTED)

EPIPE может вернуться если соединение с 127.0.0.1 -> на 127.0.0.1 и
произошёл разрыв.


В итоге. Чтобы написать нормальную прогрмму надо проверять все виды
ошибок после каждого recv() и send(). Плюс помнить, что recv() может
вернуть 0. считать это ошибкой или нет - в зваисимости от контекста.
send() никогда не может вернуть 0.

Reply all
Reply to author
Forward
0 new messages