LINUX.ORG.RU

Пинг-Понг пересылка для поддержки конекта

 


0

0

Приветствую участников форума! Вопрос по большей части относительно фаерволов.
Разрабатывается простой клиент-серверный сервис, клиент подключается по протоколу tcp к этому сервису и устанавливается соединение, но как-бы данные не пересылаются, а просто клиент ожидает поступления данных от сервера.
Стоит ли ожидать каких либо действий со стороны фаервола в отношении таких соединений?
Думаю сделать типа пинг-понг пересылку с интервалом для ожидающих клиентов до поступления целевых данных, потом как только пересылка важных данных закончена, опять переводить в пинг-понг режим до поступления очередной порции данных.

Ответ на: комментарий от domik_v_derevne

А запрос на соединение с проксиком по socks4a...

Можно и своим кодом реализовать даже без libcurl. Надо просто помнить что мы соединяемся с неким прокси (адрес:порт) и туда, если это socks4a-прокси, кидаем в качестве параметров запроса адрес 0.0.0.1 и имя целевого сервера, куда нам надо. Ну и указываем что это соединение типа socks4a, В сети можно нагуглить примеров, даже на похапе. Т.е., веб сервер будет делать такую работу для наших целей. Возможно, даже без уведомления владельца данного сервера, всякое бывает... =)))

Единственное что, надо просто помнить что у проксика по адресу соединения могут приниматься не только по дефолтному для проксей порту 1080, а например, по 80. Или по 443 или по 8443. Т.е., как он там сконфигурирован, так и будет принимать. Тогда в трафике, идущем из сети, для одмина даже напрягов вызывать не будет. Стандартный http трафик. Порты стандартные. Дёргаться ни к чему. =)))

Если про ssh, то тут я бы рекомендовал lbssh2, но да, это дополнительная либа. Хотя, многие вещи с её помощью, при наличии именно ssh-соединения делать намного проще и удобнее. То же копирование файлов через scp или самописный аналог. Ну, например, документы там какие скоммуниздить... Такое пишется при наличии гарантированного ssh-соединения (гарантий того, что одмин его не рубанёт) за полчаса. Впрочем, если бы не печальная необходимость в либе, то по ssh можно и на 80 порт ломиться, если сервер нас будет готов принять. Одмины редко парсят исходящий трафик. Скорее, порты/имена хостов. Имя хоста может быть типа, например, tbn.какой-то.хост. Т.е., выглядеть это будет для одмина типа случайное обращение к какой-то рекламной сети. Но тут бы на объём трафика ещё смотреть.

В общем, тема флуктуационного анализа трафика слишком сложна и объёмна даже для комментов. Это много и надолго. =)))

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

Запоминаешь время последнего удачного чтения из данного сокета, а когда будет достигнут таймаут, просто рубить соединение. Т.е. решается проблема дизайном алгоритма, не нужно гонять постоянный траффик.

То есть, если мне надо на сообщение от сервера реагировать не позднее, чем через 10 секунд, то пока не придёт сообщение, соединение будет раз в 10 секунд рубиться? По-моему лучше байт данных и TCP ACK гонять, чем полноценный TCP handshake.

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

Для обычного ПО полагаться на keep alive не самая лучшая идея. Если сервер не успеет послать ack на выход(например это вероятно, если произвести сбой по питанию), то при дефолтных настройках твой read провисит пару часов, в ожидании ответного ack на keepalive, вместо реконнекта. А в случае интернета, это так же справедливо ко всем участникам маршрута. Не просто так умные люди костылят свой механизм поверх.

Не, если у тебя ПО не для десктопа, и ты можешь заставить кастомера конфигурять как клиент так и сервер(или хотя бы сервер), то можно штатными механизмами обойтись.

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

Точнее не так, если ack на keepalive таки придёт, и после этого сервер помрёт без разрыва соединения. Вот тогда будет подвисон. Это довольно редкий кейс в наши дни, но я такое отлаживал.

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

Тогда про то, что сервер тебе что-то пытался безуспешно слать узнаешь только через 10 минут.

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

Точнее не так, если ack на keepalive таки придёт, и после этого сервер помрёт без разрыва соединения. Вот тогда будет подвисон.

Почему? Отвалится при следующем keepalive. Или при попытке что-нибудь этому серверу отправить.

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

Это потому что нефиг в программе лепить синхонный вызов чтения из сокета без проверки количества доступных для чтения байт.

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

Ну, следующий keep alive на оффтопике например из коробки будет через 2 часа. При попытке отправить - да отвалится. Но, если ты спишь в read(ждёшь события от сервера, например это какой то фид с теми же данными о погоде или ещё какой то редкой телеметрией), то о проблеме ядро тебе сообщит через пару часов.

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

Да что ты говоришь :) Где же должно спать такое ПО? Процом шуршать всё время? Да даже если у шуршать - как это поможет? Данных нет, будешь рвать линк и переподключаться? В любом приличном датацентре тебя за такое забанят, а в пендостане к тебе ещё и органы соответсвующие выедут :)

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

Разумеется в цикле нужно небольшой sleep делать. Это детали. Далее, если нет данных определенное время на сервере - рубишь коннект или не рубишь - пусть висит до момента, когда потребуется что-нибудь отправить туда, а при записи уже сработает ошибка со всеми вытекающими.

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

То-то все хорошие сервера столько слипов содержат.

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

Особенно, небольшой слип хорошо сработает для прекрасных высокопроизводительных протоколов когда после пару часов простоя тебе за секунду 5-10 тысяч записей прилетает.

Я не знаю, возможно я как то неправильно тружусь, но в моей практике, вызов sleep обычно всегда ассоциируется с костылём, если тебе где то надо безусловно уснуть(ну как безусловно, всё же точка отмены...), то ты что-то делаешь не так.

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

Дык да!

Я тоже про то же! Тут надо понимать что за задача. Если по дефолту прокатит, то это один разговор. А если нет, то нужна реальная настройка сервака или серваков на поддержание соединений. Заказная. И это определяется на этапе проектирования протокола. Т.е., что за протокол, какие к нему требования, каковы реакции... Всё это надо учитывать. А не просто — мы свелосипедили поддержку keep-alive в своём протоколе!!!11адын-адын... И тут вопрос — а нахрена вы это сделали, если согласно Т.З. устройства выходят на сеанс связи раз в сутки. Объём передаваемых данных — вообще уржаться, 67 байт пейлоада и сколько-то там на заголовки. Нахрена тут keep-alive?

ТС, если я не ошибаюсь, помянул там SMPP. Если я правильно понимаю о чём речь, то это протокол передачи SMS over TCP/IP. Я когда-то писал кое-что для этого дела. Версия 3.4 была использована, хотя, уже на тот момент была версия 5.х протокола, но у нас у ОпСоСов пацаны сидят ленивые и софт менять просто так они не будут. Ну так да, те сервера, которые обслуживают этот протокол, маловероятно что там будет ещё что-нибудь крутиться типа веб-сервака. Там можно и нужно использовать системные настройки. Затачивать сервера именно под этот протокол.

В среднестатистическом же случае, когда на одном хосте и веб-сервер и мускуль и ещё хер пойми что болтается, этот подход не айс. Для одного прикладного протокола надо одно, для другого другое, а третьему это вообще не надо и противопоказано. Вот и велосипедят свой вариант keep-alive для решения своих задач. Например, на веб-сервере соединение одно с клиентом, в страничке html есть пара css, десяток скриптов на javascript и сама по себе страничка состоит из нескольких запросов к некой базе данных, возвращающих xml или json. Ну чисто например. Тогда, при запросе одного URL, мы должны получить всё это добро. Вот и получается что запрос URL один, а пока сервак не отдаст все элементы данного html-документа (а там может быть и xml или json, генерируемые скриптом на серваке по некой базе, я напоминаю, т.е., это тебе не статику сплюнуть), сервак соединение не закроет. Это удешевляет стоимость обслуживания соединения, т.к. в противном случае, без keep-alive, на каждый элемент документа html нужно будет генерировать свой запрос с TCP handshake, а в случае использования ssl, ещё и ssl handshake. Это дорого по затратам.

Вот зачем нужен keep-alive на уровне протокола прикладного уровня.

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

Тут всё просто...

Я не знаю, возможно я как то неправильно тружусь, но в моей практике, вызов sleep обычно всегда ассоциируется с костылём, если тебе где то надо безусловно уснуть(ну как безусловно, всё же точка отмены...), то ты что-то делаешь не так.

Чуваки пока не открыли для себя механизмы асинхронного программирования сокетов и epoll() в частности. Бывает. На деле да. sleep это плохо. Это очень плохо. Это херовая реализация протокола.

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

Вот поэтому нужно постоянно гонять трафик. Отправляешь раз в 10 секунд пакеты, на которые сервер не реагирует и ловишь TCP ACK. Впрочем, тут уже написали, что можно TCP keepalive настроить с тем же результатом (там, где он есть). Но это тоже «постоянно гонять трафик».

monk ★★★★★
()
Ответ на: Тут всё просто... от anonymous

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

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

Раз тут упомянули про асинхронную работу, то в ней sleep не нужен, как вы все понимаете.

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

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

Например, есть такой протокол FIX, для торгов на биржах в основном используется, так вот там народ дикий, им бы побольше денег да побыстрее, а не это всё с чтением rfc и документации к системному api.

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

вот кстати недавно столкнулся с похожим говном поверх вебсокетов - если в течении минуты пакеты не приходят, ктото (тило браузер толи сервер) рвет коннект. пробовал с разных провайдеров, браузеров и стран, везде одна хрень. сервер мне неподконтролен, как в браузере это сконфигурить я ненашел. такчто шлю пустой пакет раз в минуту если небыло никакой камуникации. вот тебе и низкоуровневый keepalive в tcp\ip стеке

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

Зачем поверх tcp/ip (который обеспечивает гарантированную доставку) наворачивать логику подверждения на уровне приложения?

Это вкратце так просто. А на практике TCP/IP обеспечивает гарантированную упорядоченную доставку данных до... драйвера TCP/IP стека. И всё.

К тому же если TPC/IP ACK не пришёл, это не означает, что приложение успешно не получило последние отосланные данные.

Т.е. в первом случае: отослал данные, получил ACK, а до приложения они так и не дошли. А во втором: отослал данные, не получил ACK, а они успешно дошли и были обработаны. Именно поэтому и приходится предусматривать подтверждения на уровне приложения.

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

отослал данные, получил ACK

Что, кстати, абстрактно и на практике в user space недостижимо, см. man send:

RETURN VALUE
On success, these calls return the number of bytes sent.

Т.е. ни о каком полученном ACK или гарантии доставки успешно отправленных данных речи нет.

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

Его тут нет...

Я про

низкоуровневый keepalive в tcp\ip стеке

Это явно настройка web-сервера. Просто потому, что для уверенного утверждения того, что это именно общесистемная настройки такая, надо бы проверить тогда именно её.

Как правильно сказали выше, по дефолту она составляет 7200 сек. Проверить просто

cat /proc/sys/net/ipv4/tcp_keepalive_time
.

Если бы она была модифицирована, то тогда любое соединение рвалось бы через минуту. Для websockets есть решение, оно изложено здесь https://tools.ietf.org/html/rfc6455#section-5.5.2 Проблема заключается в том, что websockets это протокол прикладного уровня и он опирается на свои механизмы. Потому, например, что тот же трафик http ходит через проксик. В этом случае мы можем только узнать жив ли проксик или помер. Но не то что жива ли сторона, с которой установлена связь или померла. Так что, tcp keep-alive в данном случае и не было и нет и быть не могла.

Смотрите настройки своего серванта.

как в браузере это сконфигурить я ненашел.

Ссыль выше. Шлите фреймы с Opcode = 0x9 для ping и принимайте/обрабатывайте с Opcode = 0xa. Пример здесь https://gist.github.com/Jxck/3171239

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

Нет. Не так.

http://www.ietf.org/rfc/rfc1122.txt , стр. 95-96, раздел 4.2.3.2 When to Send an ACK Segment (правда, про delayed ACK, но всё же). Т.е., так делают чтобы не слать на каждый сегмент данных свой ACK. В самом общем случае Ваше утверждение неверно. Нет. ACK шлётся именно удалённой стороной и ни чем и ни кем иным. Правда, смотреть надо, например, при отключённом алгоритме Нэйгла (т.е., socket с опцией TCP_NODELAY) будет случай именно для delayed ACK, но ни какой речи о доставке системными вызовами данных только до модуля сетевой карты или до буферов ядра речи нет.

От программиста обработка ACK, равно как и иных состояний благополучно скрыта. Даже в случае RAW-sockets, которые позволяют бОльшую свободу.

В принципе, я бы рекомендовал почитать Стивенса всё таки.

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

Считайте это...

Т.е. ни о каком полученном ACK или гарантии доставки успешно отправленных данных речи нет.

Считайте это защитой от дурака. Правда, скромненькой. Но она работает. Вы же не на полном серьёзе заявляете что хотели бы анализировать флаги TCP пакета в прикладном решении? Или я ошибаюсь?

За Вас работает стек. Доставлены данные? Доставлены. send() вернёт число переданных байт. Не доставлены по какой-то причине? Получите -1 в качестве возвращаемого значения и errno будет установлен, например, в ECONNRESET (соединение закрыто другой стороной). Больше ни чего придумывать не нужно, как бы не хотелось.

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

Иначе извините, но ни чего не будет работать. Либо это не TCP, а UDP.

Moisha_Liberman ★★
()
Ответ на: Нет. Не так. от Moisha_Liberman

Нет. Не так.

Не понял, что именно не так.

От программиста обработка ACK, равно как и иных состояний благополучно скрыта.

Вот поэтому приходится полагаться на документацию к конкретной реализации TCP/IP стека, а при необходимости лезть в её код.

gag ★★★★★
()
Ответ на: Считайте это... от Moisha_Liberman

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

Конечно нет, достаточно позаботиться о подходящем контроле, что именно уже получено, на уровне приложения.

За Вас работает стек. Доставлены данные? Доставлены. send() вернёт число переданных байт.

Доставлены и отосланы это не одно и то же.

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

Отвечу одним комментом.

Батенька... А идите-ка Вы Стивенса и маны покурите? Я конечно, Ваш юмор оценил, смешно, но только не для технического форума.

Я вынужден Вас огорчить, но Вы ровным счётом ни хера не понимаете в программировании сокетов в общем и целом и TCP-сокетов в частности.

Итак, по пунктам.

Не понял, что именно не так.

В комментариях Пинг-Понг пересылка для поддержки конекта (комментарий) и Пинг-Понг пересылка для поддержки конекта (комментарий) не так всё, вообще всё. Эти комментарии написаны оленем, в принципе не понимающем работы TCP. Этот олень даже не понимает что TCP это семейство протоколов, с надёжной доставкой данных. Это написано оленем, который не удосужился не то чтобы Стивенса и маны вкурить, тут даже нет понимания простой википедии, где сказано (https://ru.wikipedia.org/wiki/Transmission_Control_Protocol):

Механизм TCP предоставляет поток данных с предварительной установкой соединения, осуществляет повторный запрос данных в случае потери данных и устраняет дублирование при получении двух копий одного пакета, гарантируя тем самым, в отличие от UDP, целостность передаваемых данных и уведомление отправителя о результатах передачи.

Механизм квитирования, да-да-да... тот самый, присылаемый с другого конца соединения ACK, это и есть одна из мер повышения надёжности доставки. А уж как там стек TCP разберётся с retransmission, это вообще не дело прикладного приложения. Вы же мне изволили излагать что:

Т.е. ни о каком полученном ACK или гарантии доставки успешно отправленных данных речи нет.

Странно... У всего интернета есть, а у Вас нет. Вы точно о TCP тут рассказывали такие страшные сказки?

Вот поэтому приходится полагаться на документацию к конкретной реализации TCP/IP стека, а при необходимости лезть в её код.

Вам, баклану, в код лезть ненадо. Лишнее. Просто потому, что те же упомянутые выше функции connect() (без которой нет возможности использовать send()) и send(), которая в TCP без connect() не работает, это POSIX. И Вам, если отбросить в сторону Ваши россказни, следовало бы усвоить что в любой POSIX-compat. системе, а Linux и *BSD это именно они, эти все функции работают абсолютно сходным образом. Причина в том, что Вы явно не знаете что стандарты POSIX гарантируют нам совместимость на уровне исходных кодов, т.е. API, а не на уровне реализаций, т.е. ABI. И Вы можете не ссать, ф-я http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html будет работать одинаково везде, где заявлено её наличие. Обломаю Вас сразу. Даже в QNX и виндах, т.к. винды отчасти, но совместимы со стандартом. И в любом случае в начале идёт connect(), устанавливается соединение, а только потом send(). А уж как там оно внутри устроено, так это вообще не Ваша головная боль. Вы прописных истин не осиливаете, а лезете в рассуждения про некие там тайные реализации. Вам этого делать явно не стоит.

Конечно нет, достаточно позаботиться о подходящем контроле, что именно уже получено, на уровне приложения.

Да? И каким же способом Вы решили самостоятельно проконтролировать поток байт с неизвестным содержимым (а зачем передавать известные данные, не проще их из кеша взять?).

Если бы Вы хотя бы раз тот же http попытались программировать, то с удивлением бы заметили что максимум что есть, это просто объём данных. Content-Length. Всё. Больше у Вас на уровне протокола нет ни хрена ни какого контроля. А вот доставка именно TCP, она вообще ни хера не знает о размере доставляемых данных. Она (стек TCP) работает без знания об http и стеку в принципе похер какой там протокол прикладного уровня гоняется и сколько байт сервер скинет клиенту. Его дело простое — пока в буфере есть данные и нет ошибки, передавай. Или пока данные прилетают на вход, принимай. Есть ошибка? Попытка retransmission. Пропала ошибка? Качаем данные. Не пропала — уведомляем приложение ошибкой. Всё. Какие тут ещё страшные сказки?

Так что, Вы и здесь ни хера не понимая написали какую-то херню.

Я только добавлю существенный момент (о чём и говорил выше и раньше). В веб-серверах используют реализацию keep-alive на уровне прикладного протокола только с одной целью — разгрузить сервер от бесцельно висящих соединений, т.к. файловые дескрипторы это ресурс и довольно дорогой. Всё. Больше незачем.

Доставлены и отосланы это не одно и то же.

Милейший, скажите, Вас башкой в пол рожали? Не, я серьёзно. У Вас без соединения данные и не отсылаются (нет соединения, send() вернёт ошибку для TCP) и они не доставляются. Если соединение есть (а TCP это семейство протоколов с установлением соединения) то данные будут и отосланы и доставлены.

Короче, по совокупности фактов. Приговор. Читать маны, Стивенса. Бегом!

Я из спора с Вами вышел, т.к. читать Вам курс лекций вместо Вашего препода, который пытался Вас научить чему-то, отдалённо напоминающему программирование сокетов в Вашем ГПТУ, я не подписывался. В соревнованиях по натягиванию совы на глобус (да, я сделал контрольный выстрел в Ваш профиль просто по привычке), я так же не подписывался принимать участие. Так что, пальма первенства тут у Вас.

Я могу понять когда люди хотя бы слегка имеют представление об обсуждаемых вещах. Но когда они несут херню, то это просто трата моего бесценного времени.

Точка в общении с данным username. В части программирования TCP он бесперспективен.

Moisha_Liberman ★★
()
Ответ на: Отвечу одним комментом. от Moisha_Liberman

Эти комментарии написаны ...

Юмор, не юмор, но с переходом на личности и я ставлю точку в дискуссии с вами.

gag ★★★★★
()
Ответ на: Его тут нет... от Moisha_Liberman

Смотрите настройки своего серванта.

я ведь написал, что сервер 3rd-party, со своим сервером все тривиально

Ссыль выше. Шлите фреймы с Opcode = 0x9 для ping и принимайте/обрабатывайте с Opcode = 0xa

мы ведь тут не про пустое болобольство и умничанье - да? из браузера нельзя ручками послать пинг-фрейм, это должен делать сам браузер, но на текущий момент ниодин из популярных этого не умеет. кроме того нет способа даже проверить, поддерживает ли текущий браузер сей механизм. ну а со стороны сервера его не послать, если сервер 3rd-party.
в моем случае повезло, что сервер игнорирует пустые сообщения, и можно реализовать кипэлив на прикладном уровне.

и давайте плиз без оскорблений и гонора - ато напоминаете небезизвестного столярова, а это фу

genryRar ★★
()
Ответ на: Отвечу одним комментом. от Moisha_Liberman

И Вы можете не ссать, ф-я http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html будет работать одинаково везде, где заявлено её наличие

Прямо по ссылке написано:

Successful completion of a call to send() does not guarantee delivery of the message. A return value of -1 indicates only locally-detected errors.

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

Хммм...

я ведь написал, что сервер 3rd-party, со своим сервером все тривиально

Я без малейшего понятия что понимается под словом «сервер» в данном случае. В моём понимании «свой сервер» это машина с виртуалками в неком ДЦ, на колокейшоне. При чём сама машина это моя собственность, просто размещена там. Виртуалки полностью под нашим контролем, всё что там установлено ставили мы либо разрабатывали мы. Т.е., все настройки и самих систем и прикладного софта целиком и полностью наши. Вот вообще все. Ну может быть и не виртуалки, это не важно. Иногда мы идём навстречу заказчикам и выделяем им по отдельному физическому серверу. Если у заказчика на это есть деньги. Что там в случае с localhost я даже догадываться пытаться не буду. Или что там с кривой реализацией.

из браузера нельзя ручками послать пинг-фрейм, это должен делать сам браузер, но на текущий момент ниодин из популярных этого не умеет. кроме того нет способа даже проверить, поддерживает ли текущий браузер сей механизм. ну а со стороны сервера его не послать, если сервер 3rd-party.

Сам браузер пинг-фреймы не шлёт. Этим занимается сервер. Браузер только возвращает pong-фрейм, причём самостоятельно и без участия или уведомления пользователя. Пользователю и знать об этом ненужно, не его дело. Но коммуникации контролирует сервер. Реализация ping-pong для сервера штука сравнительно простая. По крайней мере, мы работаем с библиотеками libwebsockets (каноничная реализация, для «больших систем»), cwebsocket для систем типа OpenWRT, всё работает нормально на стороне сервера, всё отслеживается. Если хочется чисто свою реализацию (хотя, зачем, для той же OpenWRT cwebsocket выше крыши), то вот человек свой вариант написал для OpenWRT с поддержкой ping-pong https://istarik.ru/blog/programmirovanie/73.html Правда, я без понятия зачем он это сделал, но посмотреть как на стороне сервера реализуется ping и обработка pong там можно. Наверное, человек хотел просто разобраться как это работает. Не знаю.

Собственно, самое главное здесь в другом. Ссылок выше вполне достаточно чтобы написать нормальный сервер, который будет гарантированно работать, а не рвать соединение через минуту. Они там чё, подозревают Вас в организации DoS/DDoS что ли, чтобы закрывать так соединение? Так что, либо с хостером проблема, либо свой сервер надо писать и ставить туда. Но нормального тут нет ни чего.

Заодно замечу что я не припоминаю чтобы я писал где-то что из браузера ping frame шлётся. Если Вы читали RFC 6455, то там явно сказано в п. https://tools.ietf.org/html/rfc6455#section-5.5.3:

If an endpoint receives a Ping frame and has not yet sent Pong frame(s) in response to previous Ping frame(s), the endpoint MAY elect to send a Pong frame for only the most recently processed Ping frame.

Endpoint это и есть браузер. Но ни как не сервер. Так что, я такой дури что типа из браузера ping frame шлётся и не писал и не собирался. Я читал RFC 6455.

в моем случае повезло, что сервер игнорирует пустые сообщения, и можно реализовать кипэлив на прикладном уровне.

Такие вещи рано или поздно плохо заканчиваются, но дело Ваше. Я бы поопасился такой реализации в продакшоне. Какие там ещё косяки могут быть, это тема отдельного разговора.

и давайте плиз без оскорблений и гонора - ато напоминаете небезизвестного столярова, а это фу

Простите, я без понятия кто этот ваш Столяров и чем знаменит, но когда пятизвёздочный на ЛОРе прилаживается срать в уши насчёт реализации TCP, его ловят за руку и суют носом в его же говно (враньё), а он вместо того, чтобы как мужик включает тут сказки про «переход на личности», то вот лично для меня такое поведение коньяка в отношении стека TCP/IP да, является оскорбительным. Мне было бы похрен, если бы мы обсуждали сиськи или котиков. Даже было бы похрен если бы обсуждали патчи KDE под FreeBSD. Даже можно было бы поспорить с pon4ik про горизонтальное масштабирование серверов websockets на С. Хотя, где горизонтальное масштабирование и где например, OpenWRT? =)))

Понимаете? Но когда коньяк выдаёт что-то типа того, что он нёс выше, то вот это и является оскорблением. Ведь потом кто-то найдёт же в гугле эту тему и скажет «блин, да ЛОР-регистранты настолько тупы, что даже не понимают как TCP работает...». Вот это было бы стыдно, да. А остальное это было не оскорбление. Это была констатация печального факта и не более.

Moisha_Liberman ★★
()
Ответ на: Хммм... от Moisha_Liberman

Ээээ... Поправлю.

чтобы как мужик

Надо читать «вместо того, чтобы как мужик признать свою неправоту, т.к. со всяким бывает», включает тут сказки про «переход на личности»... И далее по тексту.

Надеюсь, это понятно.

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

В Вашем случае маны это лишнее.

Прямо по ссылке написано:

Хорошо. Проверяем что же там «написано по ссылке, прямо».

Содаём простой типа сервер с tcp-соединениями, а так же блекджеком и шлюхами.

#!/bin/bash

while true;
	do nc -l localhost -p 31337;
	done
.

Вполне пойдёт, т.к. нам тут не сервер важен, а клиент. Считаем что это у нас типа сервер, который запускается как ./tipa_srv.sh Ok, запустили.

Пишем простецкий tcp-sender.c Задача — тупо установить connect() с нашим типа сервером и так же тупо просто гнать туда одну строку. В случае возникновения ошибки, вывести её в консоль. Больше нам тут ни чего не нужно, насчёт обработки ошибок можно не особо париться, код чисто иллюстративный.

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
#define _GNU_SOURCE
#include <stdio.h>
#include <err.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>

const char *srv_name  = "localhost";
const int  srv_port   = 31337;
const char *data_to_send = "Есть соединение.\n";

int main(int argc, char *argv[]) {
	int sock, n = 0, rc = 0;
	struct sockaddr_in srv_ads;
	
	memset(&srv_ads, 0, sizeof(srv_ads));
	srv_ads.sin_family = AF_INET;

	inet_pton(AF_INET, srv_name, &srv_ads.sin_addr);
	srv_ads.sin_port = htons(srv_port);
	if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
			  errx(1, "%s", strerror(errno));
	}
	if(connect(sock,(struct sockaddr*)&srv_ads, sizeof(srv_ads)) < 0) {
		errx(1, "%s", strerror(errno));
	}
	printf( "Вот мы установили соединение и начали слать данные.\n");
	while(1) {
		rc = send(sock, data_to_send, strlen(data_to_send), 0);
		if(rc == -1)
			errx(1, "%s", strerror(errno));
	}
	/* Сюда не попадём. И сокет можно не закрывать, да.
	 * По завершении процесса система всё сама за ним зачистит.
	 */
	return EXIT_SUCCESS;
}

Запускаем клиент во второй консоли, втыкаем в первую консоль, где типасервер запущен. Останавливаем наш импровизированный «сервер», нажав Ctrl+C.

Удивляемся тому, что будет выведено в консольке, где был запущен клиент. Там будет написано tcp-sender: Connection reset by peer. Хорошо. А теперь пробуем запустить всё тот же tcp-sender БЕЗ ЗАПУЩЕННОГО типа сервера. Просто, на сухую. Получим сообщение tcp-sender: Connection refused. Странно, программа одна, а сообщения разные? А почему там не написано например, «server dinn't started»?

Всё верно. Так и должно быть. Стек tcp знает только своё локальное состояние. Что там на удалённой стороне он без понятия.

Вот почему в man написано A return value of -1 indicates only locally-detected errors. Да, локальный стек отловил ошибку. Но с чем она связана он без понятия. Что там произошло? Сервер не запустили? Пьяный экскаваторщик ковшом кабель порвал, сгорел роутер или коммутатор и сервер внезапно оказался недоступен? Стеку tcp похрен. Произошла ошибка, он выплюнул о ней сообщение. Всё. Ожидать большего от стека не нужно.

В остальных случаях, когда соединение установлено, сообщения будет и отправлены и доставлены.

Батенька! Вам не нужно читать маны. Смысла нет. Это просто трата времени в Вашем случае, т.к. к прочтению мана надобно ещё и понимание прочтённого. А с этим, как я правильно понимаю, всё сложно. У Вас.

Sad but true...

Moisha_Liberman ★★
()
Ответ на: В Вашем случае маны это лишнее. от Moisha_Liberman

Пишем простецкий tcp-sender.c Задача — тупо установить connect() с нашим типа сервером и так же тупо просто гнать туда одну строку. В случае возникновения ошибки, вывести её в консоль. Больше нам тут ни чего не нужно, насчёт обработки ошибок можно не особо париться, код чисто иллюстративный.

И что этот пример показывает? Что send() может вернуть ошибку?

Напомню оригинальную формулировку:

За Вас работает стек. Доставлены данные? Доставлены. send() вернёт число переданных байт.

Речь о том что данные могут быть не доставлены в момент завершения вызова send(). Они будут доставлены в будущем, может быть, если соединение не оборвётся. Всё что возвращает send() это количество байт которые ядро себе положило в буфер.

А эту часть я просто процитирую, чтобы все видели твой культурный уровень:

Батенька! Вам не нужно читать маны. Смысла нет. Это просто трата времени в Вашем случае, т.к. к прочтению мана надобно ещё и понимание прочтённого. А с этим, как я правильно понимаю, всё сложно. У Вас.

anonymous
()
Ответ на: Хммм... от Moisha_Liberman

Мне очень сложно, читать посты такого размера, на данном ресурсе, т.к. формат слегка другой. Можно краткую выжимку - зачем я был кастанут и при чём тут вебсокеты?

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

Полная херня.

Утверждение:

Речь о том что данные могут быть не доставлены в момент завершения вызова send(). Они будут доставлены в будущем, может быть, если соединение не оборвётся. Всё что возвращает send() это количество байт которые ядро себе положило в буфер.

Ни как не соотносится с приведённой Вами цитатой из man:

A return value of -1 indicates only locally-detected errors.

Стек tcp уже определил что есть ошибка, уже вернул -1 и выставил соответствующий errno. В таком случае tcp retransmission, на который Вы попытались переползти, типа, Вы вообще не о том речь вели, уже не сработает. Для того, чтобы хоть что-то передать в таком случае, Вам надо заново создать соединение, т.е. connect() и далее. Просто передавать на уровне user space Вы будете с того места, где была ошибка. Kernel space здесь опять не при делах.

Вы и здесь предсказуемо изволили обосраться... Не надоело? А вот мне наблюдать за Вашими попытками хоть что-то там ляпнуть типа умное, уже с души воротит...

культурный уровень

ЛОЛШТО?!? =))) Ну, если Вас, баклана безграмотного, заботит мой культурный уровень, то я думаю секс Вы любите и дорогу точно знаете. Так что, счастливого Вам пути! =)))

Так доходчиво? Культурно? =)))

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

Вот почему.

библиотека для WebSocket сервера

Но, если коротко, то для клиентской части пофиг какая либа использована. Выбор либы зависит от Т.З. и чего там использует заказчик. Хреновая идея заказчику, сидящему на Qt/KDE предлагать решение с GTK и наоборот. Заказчик не оценит.

Если для серверной, то Qt здесь не в помощь, т.к. вполне до фига сишных либ. И сервер с их помощью пишется и быстро и вполне себе быстрый. Экономичный. Хотя вон, выше я дал ссыль, там человек всё написал с нуля и без либ.

С горизонтальной масштабируемостью не всегда нужно бороться, т.к. не всегда она нужна. Например, при реализации сервера на той же OpenWRT. Кстати, не видел в таких юзкейсах реализаций на питоне и перле почему-то... =)

Ну а страданиями обезьяны, у которой внезапно повысилось wtf p/s при взгляде на код, можно пренебречь. Можно уволить эту, бестолковую обезьяну и нанять толковую. Вопрос только в деньгах.

Moisha_Liberman ★★
()
Ответ на: Полная херня. от Moisha_Liberman

Стек tcp уже определил что есть ошибка, уже вернул -1 и выставил соответствующий errno. В таком случае tcp retransmission, на который Вы попытались переползти, типа, Вы вообще не о том речь вели, уже не сработает. Для того, чтобы хоть что-то передать в таком случае, Вам надо заново создать соединение, т.е. connect() и далее. Просто передавать на уровне user space Вы будете с того места, где была ошибка. Kernel space здесь опять не при делах.

Много демагогии.

В случае обрыва соединения -1 возвращается при следующем вызове send(), а не при текущем.

Доставлены данные? Доставлены. send() вернёт число переданных байт.

Вот покажи как send() гарантирует что сообщение доставлено. Можно прибить сервер сделать send(), получить результат > 0 (доставлено несколько байт), а по факту никакого сервера уже нет.

Вы и здесь предсказуемо изволили обосраться... Не надоело? А вот мне наблюдать за Вашими попытками хоть что-то там ляпнуть типа умное, уже с души воротит...

ЛОЛШТО?!? =))) Ну, если Вас, баклана безграмотного, заботит мой культурный уровень, то я думаю секс Вы любите и дорогу точно знаете. Так что, счастливого Вам пути! =)))

Ты нормальный вообще? Со своей мамой так разговаривай.

anonymous
()
Ответ на: Вот почему. от Moisha_Liberman

Примерно вспомнил о чём речь, но к чему это в посте про хартбиты vs keep alive всё равно не догнал :)

С горизонтальной масштабируемостью не всегда нужно бороться, т.к. не всегда она нужна. Например, при реализации сервера на той же OpenWRT. Кстати, не видел в таких юзкейсах реализаций на питоне и перле почему-то... =)

Дык ктож спорит, в основном посыл был - собирать нефункциональные требования до старта проекта. И никто не спорит, что компилируемое обычно вертикально лучшее умееть, но, дороже, но не дороже чем разросшееся динамическое не покрытое тестами хотя бы на 90%.

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

В случае обрыва соединения -1 возвращается при следующем вызове send(), а не при текущем.

Строго говоря, это зависит от интенсивности вывода, размера буфера и немного от погоды на Марсетого, как отработает планировщик. Если поставить размер буфера сокета меньше самого маленького mtu на маршруте, то вполне можно иметь такой «детектор», по идее.

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

Не. Не получится.

В user space не получится.

Этот олень вон чего заявляет:

В случае обрыва соединения -1 возвращается при следующем вызове send(), а не при текущем.

Отсюда в случае обрыва соединения данные, переданные до -1 в send() уже переданы и обработаны. Просто потому, что вторая сторона соединения вернула на ранее переданные данные ACK. Если она не вернула, то тогда -1 и errno. Тогда заново connect() и передаём send() данные с того места, где остановились. Здесь даже не важно отключили мы алгоритм Нэйгла или нет. Delayed ACK или нет. -1 и errno от этого не зависят.

И он же заявляет:

Можно прибить сервер сделать send(), получить результат > 0 (доставлено несколько байт), а по факту никакого сервера уже нет.

Т.е., число переданных байт (> 0) это и есть значение, возвращаемое в user space функцией send(). В мане так и написано. Значит, ACK на переданную порцию данных получен. А вот следующие передачи данных только после успешного connect(), производимого заново. О том и речь.

Всё остальное это ЛПиНП. Даже если мы выставим MTU каким-то безумно малым, то в этом случае так же будет получаться ACK в случае успешной передачи данных и -1 в случае неуспешной. Просто tcp соединение и send() по-другому не работают.

Этот баклан ещё пытался соскочить на tcp retransmission, но эта вещь вообще не рулится из user space. Это внутренняя реализация внутри kernel space. Т.е., если есть помеха и данные не были доставлены, то сам по себе стек пытается передать их заново. Не смог? Вот тогда send() возвращает -1 и смотрим на errno.

Максимум где данные о tcp retransmisson можно увидеть, это в выводе ifconfig (TX/RX errors, dropped, overruns, carrier, collisions). Но это данные из kernel space и приложению они похрен. В user space важен только результат. Передано или нет. По этой причине и нет вариантов кроме send()/write().

Короче, на говно от этого анона пятизвёздочного и его жалкие ужимки в попытках съехать с базара и натянуть сову на глобус я, как уважающий мир животных и птиц, тратить время не буду. Он херню несёт. А сову всё таки жалко. =)))

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

Дык...

Примерно вспомнил о чём речь, но к чему это в посте про хартбиты vs keep alive всё равно не догнал :)

Я и спорить-то не собирался, если честно. Вы во многом правы. Просто так вышло, что в тот момент когда тот тред, на который я дал ссылку обсуждался, у меня в реале были примерно такие же обсуждения по поводу websockets, C и вот этого вот всего. =))) Совпадение позабавило.

А тут вон, человек пишет про сервер, который рвёт соединения раз в минуту аки Тузик грелку. Ну... Второго такого совпадения я уже просто не мог пропустить. =)))

Moisha_Liberman ★★
()
Ответ на: Не. Не получится. от Moisha_Liberman

Насколько я знаю - нет. Если покажешь в tcp подсистеме где происходит блокировка пока ack обратно не прилетит или не случится X, я поменяю своё мнение, а на практике я наблюдал поведение описанное аноном и долго втыкал в дампы, что бы понять как так.

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

Тут есть два варианта.

Надо смотреть на то, отключён ли алгоритм Нэйгла. Только в этом случае на порцию из нескольких пакетов может прилететь всего один ACK. Это называется delayed ACK. ЕМНИП, RFC 1122. Причём, здесь надо понимать что ACK шлётся в ответ на всю порцию данных, которая должна быть передана. Тогда да, если есть обрыв, приходится долго втыкать где же именно.

Если без RFC, то вот человеческое описание https://en.wikipedia.org/wiki/TCP_delayed_acknowledgment

В коде (если код унаследован и надо посмотреть на то, отключается ли алгоритм Нэйгла), надо искать что-то типа:

int flag = 1;
int result = setsockopt(sock,            /* Какой socket? */
                        IPPROTO_TCP,     /* Опция уровня TCP */
                        TCP_NODELAY,     /* Какая именно опция? Её название.*/
                        (char *) &flag,  
                        sizeof(int));    
 if (result < 0)
    /* Тут чего-то не так пошло. */

Если аналогичный этому кусок кода найден, то явно отключаем алгоритм Нэйгла и поведение стека tcp будет как я описал выше для delayed ACK. Т.е., один ACK будет на всю порцию данных. Хоть мегабайт, хоть десять, хоть двадцать, хоть 1500 байт. Это уже зависит от приложения и объёма передаваемых данных.

Если не отключён, то порция данных == один пакет. ACK будет слаться в ответ на каждый переданный пакет.

Moisha_Liberman ★★
()
Ответ на: Тут есть два варианта. от Moisha_Liberman

Ты всё правильно говоришь про протокол. Но, разве функция send занимается ожиданием ack, вместо того, что бы просто, записать данные в системный буфер?

pon4ik ★★★★★
()
Ответ на: Тут есть два варианта. от Moisha_Liberman

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

Я почти уверен, что если я полезу в ядро и найду в точности тот код, который выполняет send для SOCK_STREAM, то обратного открытия я не сделаю.

pon4ik ★★★★★
()
Последнее исправление: pon4ik (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.