![]() |
Модераторы: feodorv |
![]() ![]() ![]() |
|
NightGoblin |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1021 Регистрация: 24.11.2002 Где: 127.0.0.1 Репутация: нет Всего: 11 |
Даже не знаю с чего начать, но всё же попробую как-то упорядочить многомерную проблему
![]() Общая ситуация: Есть TCP мультиплексор соединений на C. Клиенты сервера посылают запрос и дальше по долговременному соединению получают данные. Основной вопрос: Как, игнорируя данные от клиентов, отследить их "корректное" отключение от сервера (TCP FIN)? О "вываливании", когда связь с клиентом просто потеряна (пропадание электричества, перегрызенный провод, упавший раутер, и т. п.) речи не идёт -- тут нужен другой механизм, и с ним я буду разбираться отдельно. Проблема: Зависит от того, с какой стороны смотреть. С одной стороны, poll(2) не возвращает POLLHUP когда отваливаются соединения. С другой стороны, посылаемые клиентами данные забивают буфер ввода или заставляют сервер читать ненужный мусор. С третьей, если сокет "прикрыть" по shutdown(fd, SHUT_RD), poll с events=POLLIN возвращается сразу, а read(2)/recv(2) читают 0 байт и, естественно, мы получаем все признаки закрытого соединения. Более литературно: Как уже, надеюсь, понятно, сокеты клиентов опрашиваются при помощи poll(2). Проблема в том, что хочется получить запрос от клиента и дальше игнорировать все данные -- тут вроде помогает shutdown на SHUT_RD. Пока всё хорошо. Читаем мануал к poll(2), в котором значится POLLHUP, который якобы возвращается при закрытии соединения. Так вот, он почему-то не возвращается. Гугление данного вопроса привело меня к тому, что разные ОС обрабатывают это событие по-разному: одни возвращают POLLHUP, другие POLLIN, который нужно проверять read(2)/recv(2) на наличие входных данных: если данных нет, то и толку от такого сокета -- тоже. Пока ожидается запрос от клиента, всё хорошо; только вот сокет, закрытый на чтение, заведомо вернёт POLLIN (ибо чтение из такого сокета блокировано не будет). Возвращаемся к прежней проблеме. Как сделать так, чтобы данные, приходящие от клиентов, игнорировались? Пока вижу три варианта -- ловить POLLIN и:
Первый вариант мне не нравится: почему процесс должен вообще дёргаться по поводу данных, приходящих от клиентов, когда они не нужны? Неужели нет способа их просто игнорировать? Второй какой-то "фошысский", хотя на данный момент самый симпатичный. Ну и третий тоже не подходит, потому что если буфер сокета -- пара килобайт, а клиентов -- пара тысяч, совершенно ненужный мусор съест 4 мегабайта памяти! Код: Естественно, весь код программы (хоть она и не дописана пока) приводить не буду, ниже с сокращениями:
Если нужна ещё какая-то информация о коде (или сам код) -- приведу с радостью по первому требованию. sockCtl и sockClient на данном этапе не имеют значения (кроме того, что они находятся в состоянии LISTEN), в дальнейшем их пути разойдутся. Сценарий: Запускаем сервер, телнетимся на нужный порт. Вводим данные -- всё хорошо; тыкаем ^], вводим q -- на стороне сервера видим:
после чего (поскольку read(sock)==0 обрабатывается в mux_read()) сокет захлопывается сервером. Если же порт клиента после первого mux_read() был подвергнут shutdown(SHUT_RD), а соответствующий poll.events установлен в 0, сервер вообще ничего не сообщает и продолжает радостно выдавать по точке в 5 секунд. Да, по идее mux_read() должен возвращать значение, по которому i будет декрементироваться в случае, если сокет был удалён, но это не критично (в крайнем случае, poll() уйдёт на второй круг), и расправа над этой багой запланирована на сегодняшний вечер. Большое спасибо за внимание! -------------------- Kernel panic: /dev/null overflow! GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y? B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981 |
||||
|
|||||
GrayCardinal |
|
|||
Фигасе ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3039 Регистрация: 9.11.2003 Репутация: 3 Всего: 58 |
NightGoblin,
Если данные идут не по протоколу, имеешь полное право убить нафиг ![]() Если у тебя "строковый" сервер, буфер сокета можно уменьшить байт до 256 ![]() ![]() Это сообщение отредактировал(а) GrayCardinal - 10.9.2008, 16:45 |
|||
|
||||
NightGoblin |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1021 Регистрация: 24.11.2002 Где: 127.0.0.1 Репутация: нет Всего: 11 |
GrayCardinal,
Размер буфера можно установить до приёма соединения через SO_RCVBUF -- но, насколько мне удалось выяснить, после установки соединения этот буфер можно только увеличить (http://docs.hp.com/en/B2355-90136/ch03s01.html). Проблема, собственно, в том, что нужно всё и сразу -- а существующие варианты работают только наполовину ![]() Что конкретно непонятно? Если нужно -- объясню подробнее. А вообще я сам всё больше склоняюсь к варианту "не умеешь вежливо разговаривать по протоколу -- ступай лесом" ![]() -------------------- Kernel panic: /dev/null overflow! GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y? B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981 |
|||
|
||||
MAKCim |
|
|||
![]() Воін дZэна ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5644 Регистрация: 10.12.2005 Где: Менск, РБ Репутация: 6 Всего: 207 |
NightGoblin,
сформулируй одним предложением что надо сделать? ![]() -------------------- Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі © |
|||
|
||||
MAKCim |
|
|||
![]() Воін дZэна ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5644 Регистрация: 10.12.2005 Где: Менск, РБ Репутация: 6 Всего: 207 |
после этого, я так понимаю, сервер не принимает данных от клиента, а может только возвратить результат? -------------------- Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі © |
|||
|
||||
NightGoblin |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1021 Регистрация: 24.11.2002 Где: 127.0.0.1 Репутация: нет Всего: 11 |
Определить, когда отключился клиент, сокет которого закрыт на чтение. Это один из вариантов, но это будет достаточным решением проблемы.
Именно так. -------------------- Kernel panic: /dev/null overflow! GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y? B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981 |
|||
|
||||
MAKCim |
|
|||
![]() Воін дZэна ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5644 Регистрация: 10.12.2005 Где: Менск, РБ Репутация: 6 Всего: 207 |
проверить состояние TIME_WAIT на сокете -------------------- Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі © |
|||
|
||||
NightGoblin |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1021 Регистрация: 24.11.2002 Где: 127.0.0.1 Репутация: нет Всего: 11 |
MAKCim, есть ли переносимый способ проверить состояние сокета на TIME_WAIT? В линуксовом tcp(7) есть TCP_INFO, но там написано "This option should not be used in code intended to be portable." Сервер должен работать как минимум на FreeBSD (и, желательно, на Linux, на котором ведётся разработка
![]() -------------------- Kernel panic: /dev/null overflow! GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y? B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981 |
|||
|
||||
MAKCim |
|
|||
![]() Воін дZэна ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5644 Регистрация: 10.12.2005 Где: Менск, РБ Репутация: 6 Всего: 207 |
NightGoblin,
да, TCP_INFO и POLLRDHUP не переносимы
так тут как бы POLLHUP'а достаточно ведь что просходит когда мы делаем shutdown(SHUT_RD), то клиенту посылается FIN сегмент, он отвечает на него ACK'ом на стороне сервера сокет переходит в состояние FIN_WAIT_2 после close() на сокете на стороне клиента серверу посылается FIN сегмент, сокет на сервере переходит в состояние TIME_WAIT через 2*MSL секунд сокет на сервере переходит в состояние TCP_CLOSE и poll() на нем возвращает POLLHUP так что POLLHUP достаточен для определения момента закрытия соединения -------------------- Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі © |
|||
|
||||
NightGoblin |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1021 Регистрация: 24.11.2002 Где: 127.0.0.1 Репутация: нет Всего: 11 |
MAKCim, в общем, пока что я не пробовал разбираться. Проблема получилась в том, что я написал короткий тест, и там вроде бы всё работало. Потом переписал это под рабочую версию (вроде бы, ничего не поменял) -- и всё, POLLHUP перестал приходить. Пока что сделал poll на POLLIN и отрубаю клиентов при получении новых данных (которые мне не нужны). Тоже не оптимальный способ так делать, но до поры - до времени сойдёт. В ближайшее время покопаюсь, а пока другие проблемы свалились на голову (не относящиеся к теме).
-------------------- Kernel panic: /dev/null overflow! GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y? B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981 |
|||
|
||||
![]() ![]() ![]() |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Сети | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |