Intereting Posts
C: теория о том, как извлекать файлы из архивного файла Быстрое поплавковое квантование, масштабируемое по точности? Конфликт между учебником Стэнфорда и GCC Как получить имя (путь) созданного устройства uinput Параметр повторного использования strtol Как модифицировать прошивку TI SensorTag для бесконечной рекламы? metallib: Модуль чтения ошибок: недопустимая подпись битового кода оценивать выражение с обратной косой чертой в середине выражения Является ли main () обязательным для программы C? Как проверить, что введенный пользователем номер не больше LLONG_MAX или LOWER, чем LLONG_MIN? C обычные арифметические преобразования при хранении большого положительного целого оно преобразуется в другое отрицательное число в чем преимущество статической функции? scanf собирает неправильный ввод JNI Android – Преобразование char * в байтовый массив и возврат его в java

Как узнать, заполнен ли буфер сокета?

Как узнать, заполнен ли буфер чтения сокета или буфер буфера записи пуст?

Есть ли способ получить статус буфера сокета без системного вызова?

UPDATE: Как насчет этого: я хотел бы получить обратный вызов или сигнал, когда заполнен буфер сокета чтения или буфер буфера записи пуст. Таким образом, я могу остановить обработку, чтобы позволить больше ввода-вывода происходить на проводе, так как привязка ввода-вывода всегда является проблемой при отправке данных на провод.

Вызов select() – это то, как вы проверяете, есть ли в нем буфер чтения. Не тогда, когда он заполнен (я думаю).

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

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

Независимо от того, нужен ли режим ядра для вычисления, это зависит от платформы. Смутное стремление избежать системных вызовов не является допустимым методом оптимизации.

Базовый интерфейс сокетов BSD-стиля ничего не говорит о буферах чтения и записи. Когда имеет значение, пустой буфер отправки? Это, конечно же, не означает, что все данные были получены на другом конце сокета – он может сидеть где-то в каком-то маршрутизаторе. Аналогично, ваш «заполненный» буфер чтения не гарантирует, что запись на другом конце будет заблокирована.

Вообще говоря, вы просто читаете / пишите столько, сколько можете, и пусть слой сокетов обрабатывает сложность. Если вы видите много операций ввода-вывода с небольшими размерами, возможно, есть проблемы с производительностью. Но помните, что сокет streamа будет отправлять / получать пакет за раз, содержащий блок данных. Если TCP_NODELAY не установлен, это не так, как если бы байты поступали на NIC, и вы могли бы сделать один прочитанный вызов на каждый байт. Они поступают в пакеты, поэтому, скорее всего, они станут доступны для чтения сразу, возможно, 1 к-ит за раз. Вы вряд ли сможете ускорить процесс, удержав чтение, пока вам нечего прочитать. На самом деле вы можете сделать это хуже, потому что к тому времени, когда буфер чтения вашей конечной точки будет заполнен, существует риск того, что входящие данные будут отброшены, потому что их некуда хранить, что приводит к задержкам и повторным отправкам.

Опросите файловый дескриптор с select и нулевым таймаутом – если select говорит, что он доступен для записи, буфер отправки не заполнен.

(Ох … без системного вызова. Нет, нет.)

Приложение:

В ответ на ваш обновленный вопрос вы можете использовать два ioctl s в сокете TCP: SIOCINQ возвращает количество непрочитанных данных в буфере SIOCOUTQ , а SIOCOUTQ возвращает количество неотправленных данных в очереди отправки. Я не верю, что есть какое-либо асинхронное уведомление о событиях для них, но это не даст вам опроса.

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

Прежде чем начать, перейдем к зависанию системных вызовов – вы не можете взаимодействовать с сетевыми стеками на основе ядра (* nix) без переключения и выхода из пространства ядра. Ваша цель должна заключаться в понимании функций стека, поэтому вы можете получить максимальную отдачу от своей системы.

Как узнать, заполнен ли буфер чтения сокета

На эту часть ответили – вы этого не делаете, потому что это не то, как вы должны думать.

Если отправитель (плохо) fragmentирует его TCP-фреймы (обычно из-за отсутствия буферизации маршализированных данных на выходе и с отключением алгоритма Nagle с TCP_NDELAY), ваша идея сократить количество системных вызовов, которые вы делаете, является хорошей идеей. Подход, который вы должны использовать, включает настройку «низкого водяного знака» для чтения. Во-первых, вы устанавливаете то, что считаете разумным размером буфера приема, устанавливая SO_RCVBUF с помощью setsockopt (). Затем верните фактический размер буфера чтения с помощью getsockopt (), поскольку вы можете не получить то, что вы просите. 🙂 К сожалению, не все реализации позволяют вам снова читать SO_RCVBUF, поэтому ваш пробег может отличаться. Затем определите, сколько данных вы хотите прочитать для чтения, прежде чем читать. Установите SO_RCVLOWAT с этим размером, используя setsockopt (). Теперь дескриптор файла сокета будет выбирать только как читаемый, если есть хотя бы этот объем данных, считанных для чтения.

или буфер сокета записи пуст?

Это интересно, так как мне нужно было сделать это недавно, чтобы убедиться, что мой MODBUS / TCP ADU каждый занят своими собственными кадрами TCP, что требует спецификация MODBUS (@steve: контроль fragmentации – это один раз, когда вам нужно знать, когда отправка буфер пуст!). Что касается оригинального плаката, я очень сомневаюсь, что он действительно этого хочет, и полагает, что он будет намного лучше обслуживать, зная размер буфера отправки до его начала, и периодически проверять количество данных в буфере отправки во время отправки, используя уже описанные методы. Это обеспечило бы более тонкую информацию о пропорции используемого буфера отправки, который можно было бы использовать для более плавного регулирования производства.

Для тех, кто все еще интересуется тем, как обнаруживать (асинхронно), когда буфер отправки пуст (как только вы уверены, что это действительно то, что вы хотите), ответ прост – вы устанавливаете низкий уровень водяного знака отправки (SO_SNDLOWAT) равным буферу отправки размер. Таким образом, дескриптор файла сокета будет выбран только как записываемый, когда буфер отправки пуст.

Не случайно мои ответы на ваши вопросы вращаются вокруг использования select (). Почти во всех случаях (и я понимаю, что сейчас я направляюсь на религиозную территорию!) Приложениям, которым нужно перемещать много данных (внутри и между хостами), лучше всего структурировать как однопоточные государственные машины, используя маски выбора и цикл обработки, основанный на pselect (). В наши дни некоторые ОС (Linux, чтобы назвать один) даже позволяют управлять обработкой сигнала с помощью выбора дескриптора файла. Какая роскошь – когда я был мальчиком … 🙂

Питер

Принимая во внимание, что буфер ядра для сокетов живет в kernelspace, я сомневаюсь, что есть какой-либо способ задать размер без syscall.
С помощью системных вызовов вы можете попробовать recv с PEEK.

 ret = recv(fd, buf, len, MSG_PEEK); 

Будет давать recv, но без опорожнения буфера.

Это невозможно без syscall. Но в чем проблема с системными вызовами?

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

Если вы читаете () s в отдельном streamе, SO_RCVLOWAT может блокировать это чтение, пока в буфере не будет достаточного количества данных. К сожалению, poll () и select () игнорируют эту опцию сокета, по крайней мере, в Linux и всегда проверяют наличие одного байта.

@blaze,

Linux и SO_RCVLOWAT

С уважением, мой опыт отличается от вашего. Я использую низкоуровневые водяные знаки приема в Linux с FC5, в продуктах, которые распространяют видео через IP (как UDP, так и TCP), поэтому я понимаю, насколько важно максимально использовать возможности вашего сетевого стека. На самом деле, Linux была одной из первых реализаций, позволяющих вам прочитать низкий водяной знак (и некоторые до сих пор этого не позволяют). 🙂

Вы указываете, что poll () и select () не соответствуют SO_RCVLOWAT. Я использую pselect () до тех пор, пока я помню, поэтому, возможно, проблема связана с select () и poll (). В любом случае, вы всегда должны использовать pselect () или ppoll (), если они доступны, в предпочтении более старым вызовам, потому что они могут атомарно изменять сигнальную маску программы при входе / выходе из вызова. Если вы понимаете, что это значит, тогда вы поймете, почему это важно в коммерческом программном обеспечении. Если нет, такая дискуссия оправдывает собственную нить. 🙂

Питер