LINUX.ORG.RU

Ошибка на стороне сервер


0

1

Всем привет, подскажите почему в случае если я до завершения передачи принудительно закрою клиент то сервер выдаёт ошибку. При завершении процесса закрываются все его дескрипторы и тд. тоесть отсылает сигнал FIN серверу. Сервер в это время крутит циклично write() и видимо когда соединения больше нет вылетает так как его никто не предупредил, соответственно в таких случаях нужно както особо настраивать сервер или иначе создавать сокет а не просто сокет(аф_инет, сокет стрим) бинд листен асепт. я прав? :)

Если надо будет добавить код напишите об этом.


На чем пишешь? После сокет надо закрывать со стороны сервера тоже, а ты видимо производишь какие-то действия с ним после того, как клиент завершил соединение.

sanchopanca
()
Ответ на: комментарий от sanchopanca

int count = strlen(buff); int i = 0; while(count--) { char t = buff[i++]; usleep(1000*100); write(connfd, &t, 1/*strlen(buff)*/); } close(connfd);

после установления соединения сервер пишет в буфер обмена 10 раз в секунду и клиент собсна сразу принимает данные, но если я закрою клиент ты сервер падает, на плюсах пишу. Вот в том то и дело что сервер после того как клиент закрыт продолжает писать пока не закончится счётчик.

Onito
() автор топика
Ответ на: комментарий от Onito

Сам я на плюсах не пишу, но предлагаю следующее решение.

Лови исключение из-за которого сервер падает и в обработчике исключения закрывай сокет.

sanchopanca
()

Что значит падает и о какой ошибке речь расскажешь, или религия не позволяет?

Гугли что-ли SIGPIPE/EPIPE.

arturpub ★★
()
Ответ на: комментарий от arturpub

ну в том то и дело что ошибка внутри write завершает программу, тоесть после ошибки не происходит выполнение других операторов и я не могу не экран вывести значение переменной errno или куда там пишет write её, я загуглил что ты предложил, первый вариант говорит о обмене между процессами а второй я не нашел, у меня связь через инет идёт. Подскажи как поймать такую ошибку еслиб я знал сделал бы сам

Onito
() автор топика
Ответ на: комментарий от Onito

Под отладчиком или в консоли если пишет broken pipe, значит ты схватил unix-сигнал SIGPIPE, а он по дефолту валит процесс. Если так, то надо заблочить SIGPIPE: signal(SIGPIPE, SIG_IGN); тогда write() начнет вместо этого возвращать EPIPE в errno и ты сможешь это обработать.

Тут кстати есть и другие решения: http://stackoverflow.com/questions/108183/how-to-prevent-sigpipes-or-handle-t...

arturpub ★★
()
Последнее исправление: arturpub (всего исправлений: 1)
Ответ на: комментарий от arturpub

спасибо, это и правда помогло, действительно я затупил, просто я использую в качестве иде qt creator и раньше у меня почему-то не работал нормально дебагер а сейчас запустил и всё норм, действительно то что ты написал вывел. А не подскажешь может есть более правильный способ избежать эту ошибку? Ну например создать сокет по другому или ещё что, или надо вот таким образом конфигурировать поведение сокетов?

Onito
() автор топика
Ответ на: комментарий от Onito

По ссылке парни приводили другие решения, но они непереносимые, и я про них ощем-то признаться не знал. Залочить sigpipe нормальное решение, кроме случаев, когда какая-то подключенная библиотека ставит свой хендлер и что-то в нем делает. Представить не могу, что это могло бы быть, но очевидно чей-то быдлокод. Если переживаешь, можешь запретить только временно и только для текущего треда, если тредишься.

Еще можно использовать poll/select с огромным таймаутом, они берут список дескрипторов и возвращают их состояние, poll поудобнее. Не знаю, как будет работать, попробуй, отпишешься.

arturpub ★★
()
Ответ на: комментарий от arturpub

да poll работает просто и эффективно и не вносит глобальные изменения в поведение сокетов, вот нашел ссылку на годное описание poll http://www.intuit.ru/studies/courses/570/426/lecture/9699?page=2 а про селект лучше читать в учебнике стивенса, так как это более громоздкая функция.

Onito
() автор топика
Ответ на: комментарий от Onito

вот изменённый код

struct pollfd fds;

            fds.fd = connfd;
            fds.events = POLLHUP;

            int ggg = poll(&fds, 1, 0);
            if(ggg==1)
                continue;

            char t = buff[i++];
            usleep(1000*100);
            write(connfd, &t, 1/*strlen(buff)*/);

Onito
() автор топика
Ответ на: комментарий от Onito

Дай угадаю: ты не прочитал маны и теперь недоумеваешь, почему у тебя иногда записывается не весь буфер?

devsdc ★★
()
Ответ на: комментарий от devsdc

да я знаю, это прототип который всёравно переделаю полностью как дойдёт дело

Onito
() автор топика
Ответ на: комментарий от devsdc

кстати вот интересный вопрос

char t = buff[i++];
usleep(1000*100);
write(connfd, &t, 1/*strlen(buff)*/);

вот так работает нормально

usleep(1000*100);
write(connfd, &buff[i++], 1/*strlen(buff)*/);

а вот так не работает, это связано с особенностями того как возвращается ссылка от возвращаемого объекта массива? Я не очень понимаю такие тонкости, точнее почему тут другое поведение функции write

Onito
() автор топика
Ответ на: комментарий от devsdc

олсо я знаю про указатели но использование [] более наглядно

Onito
() автор топика
Ответ на: комментарий от Onito

Ну, так-то приоритет взятия адреса меньше, чем приоритет постфиксного инкремента. У тебя сначала увеличивается i, а потом уже берётся адрес элемента. Подозреваю, это не то, чего ты хочешь.

devsdc ★★
()
Ответ на: комментарий от devsdc
#include <iostream>

using namespace std;

int main()
{
    int arr[2] = { 1, 2 };
    int i = 0;
    cout << arr[i++] << ' ' << arr[i++] << endl;
    i = 0;
    cout << arr[i++] << endl;
    cout << arr[i++] << endl;
    return 0;
}

вывод такой: 2 1 1 2

что за ересь?

Onito
() автор топика
Ответ на: комментарий от devsdc

Дай теперь я угадаю — он локализовывал эту сраную ошибку :)

arturpub ★★
()
Ответ на: комментарий от Onito

Порядок вычисления разных arr[i++] не определён. На практике получается, что второе вычисляется раньше первого.

devsdc ★★
()
Ответ на: комментарий от devsdc

лол, вот ты писал &buff[k] == buff + k а нифига, вот такое работает без проблем

usleep(1000*100); write(connfd, buff+i++, 1/*strlen(buff)*/);

Onito
() автор топика
Ответ на: комментарий от Onito

Результат множественных присвоений, а оператор++ это тоже присвоение, между sequence-point'ами не определен и может быть любым, решать компилятору. В твоем случае второй i++ вычислился в выражении раньше, чем первый.

Пример выше с write'ом должен работать, видимо он не очень неполный.

arturpub ★★
()
Ответ на: комментарий от devsdc

нееееет это мой косяк фааааак я когда привёл типо не работающий вариант я забыл закомментить строку с присвоением t и получается i дважды увеличивался из за чего ересь и была, короче мой косяк :) верный признак того что пора отдохнуть :)

Onito
() автор топика
Ответ на: комментарий от Onito

А зачем таймаут в 0 выставил? Батарейку кушать будешь, ставь -1, и что за непонятный continue, там if/else нужен по маске revents.

arturpub ★★
()
Ответ на: комментарий от false

лол нет, скобочки это разыменование и наоборот снятие указателя и возвращение конкретного объекта, вы меня не шутите

Onito
() автор топика
Ответ на: комментарий от arturpub

ну это прототип :) в нём оптимизации не нужны

Onito
() автор топика
Ответ на: комментарий от false

Не знай чо вы по пятницам до четырех сидите. Еще же в толксах флудить :)

arturpub ★★
()
Ответ на: комментарий от devsdc

а вот так тоже правильно &*(buff+i++) буду писать такую непонятную хероту тем кого ненавижу лол :)

Onito
() автор топика
Ответ на: комментарий от arturpub

int timeout - тайм-аут в миллисекундах. Если параметр timeout равен 0, poll работает в режиме опроса (возвращает управление немедленно). Если он равен -1, poll ждет готовности дескрипторов неограниченное время. есть гарантия что дескриптор после разрыва соединения прийдёт в состояние готовности?

Onito
() автор топика
Ответ на: комментарий от Onito

а вообще да, там же в ревент есть состояние разрыва соединения, так что верно глаголишь :)

Onito
() автор топика

почему людям так нравится жрать кактус?

-module(ttt).
-export([start/1, server/1]).

start(Port) ->
  {ok, Srv} = gen_tcp:listen(Port, [
    {packet, line},
    {active, true}]),
  acc(Srv).

acc(Srv) ->
  {ok, Skt} = gen_tcp:accept(Srv),
  gen_tcp:controlling_process(Skt, spawn(?MODULE, server, [Skt])),
  acc(Srv).

server(Skt) ->
  receive
    {tcp, Skt, Data} ->
      % Data is my wonderfull
      server(Skt);
    {tcp_closed, Skt} ->
      poka;
    {tcp_error, Skt, _} ->
      tozhe_poka
  end.

nanoolinux ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.