Есть ли способ очистить POSIX-сокет? - PullRequest
35 голосов
/ 13 мая 2009

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

Ответы [ 8 ]

25 голосов
/ 13 сентября 2011

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

send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
int flag = 1; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
send(sock, "important data or end of the current message", ...);
flag = 0; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));

Как написано на man-страницах Linux

TCP_NODELAY ... установка этой опции вызывает явный сброс ожидающих результатов ...

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

16 голосов
/ 13 мая 2009

Для сокетов Unix-домена вы можете использовать fflush(), но я думаю, что вы, вероятно, имеете в виду сетевые сокеты. На самом деле не существует концепции их очистки. Ближайшие вещи:

  1. В конце сеанса вызывается shutdown(sock, SHUT_WR) для закрытия записей в сокете.

  2. В сокетах TCP отключение алгоритма Nagle с помощью sockopt TCP_NODELAY, что, как правило, ужасная идея, которая не будет надежно делать то, что вы хотите, даже если кажется, что она позаботится об этом при первоначальном исследовании. *

Весьма вероятно, что обработка любой проблемы, вызывающей «сброс» на уровне протокола пользователя, будет правильной вещью.

8 голосов
/ 25 апреля 2013

В RFC 1122 имя того, что вы ищете, это «PUSH». Хотя я не знаю ни одного TCP API, который реализует "PUSH".

Некоторые ответы и комментарии касаются алгоритма Nagle. Большинство из них, похоже, предполагают, что алгоритм Nagle задерживает каждую отправку. Это предположение неверно. Nagle откладывает отправку только тогда, когда предыдущий пакет еще не был подтвержден (http://www.unixguide.net/network/socketfaq/2.11.shtml).

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

Одно из решений состоит в том, чтобы избежать этих «последующих пакетов». Если ваше приложение вызывает send () более одного раза для передачи одного составного запроса, попробуйте переписать ваше приложение. Соберите запрос в пространстве пользователя, затем позвоните send(). Один раз.

Кроме того, когда буфер отправки содержит достаточно данных, чтобы заполнить максимальный размер сетевого пакета, Nagle также не задерживает. Это означает, что Nagle (действительно) не задерживает массовую отправку, даже если вы send() массовые данные в маленьких кусках.

7 голосов
/ 13 мая 2009

В стандартном интерфейсе сокетов TCP / IP, о котором я знаю, не существует способа очистки данных «на всем протяжении до удаленного конца» и обеспечения их фактического подтверждения.

Вообще говоря, если вашему протоколу требуется передача данных в режиме реального времени, обычно лучше всего установить setsockopt() из TCP_NODELAY. Это отключает алгоритм Nagle в стеке протоколов, а write () или send () в сокете более точно сопоставляются с отправками в сеть .... вместо того, чтобы реализовывать удержания отправки, ожидающие появления дополнительных байтов и использующие все Таймеры уровня TCP, чтобы решить, когда отправлять. ПРИМЕЧАНИЕ. Отключение Nagle не отключает скользящее окно TCP или что-либо еще, поэтому это всегда безопасно… но если вам не нужны свойства «реального времени», накладные расходы на пакет могут значительно возрасти.

Кроме того, если обычные механизмы сокетов TCP не подходят для вашего приложения, то, как правило, вам необходимо использовать UDP и создавать собственные функции протокола на основе базовых свойств отправки / получения UDP. Это очень часто встречается, когда у вашего протокола есть особые потребности, но не стоит недооценивать сложность того, как сделать это хорошо и получить все это стабильно и функционально правильно во всех, кроме относительно простых приложениях. В качестве отправной точки, тщательное изучение конструктивных особенностей TCP позволит пролить свет на многие вопросы, которые необходимо рассмотреть.

1 голос
/ 13 мая 2009

Я думаю, что это будет чрезвычайно сложно, если не невозможно, правильно реализовать. Что означает слово «флеш» в этом контексте? Байты передаются в сеть? Байты, подтвержденные стеком TCP получателя? Байты, переданные в приложение пользовательского режима получателя? Байты полностью обработаны приложением пользовательского режима?

Похоже, вам нужно сделать это на уровне приложения ...

0 голосов
/ 19 июля 2014

Использовать fsync ():

sock_fd - целочисленный дескриптор файла из вызова сокета (..., ...)

FSYNC (sock_fd);

0 голосов
/ 13 декабря 2011

Вы можете установить опцию tcp SO_LINGER, чтобы установить определенный таймаут, а затем закрыть сокет, чтобы убедиться, что все данные были отправлены (или обнаружены сбои в этом) после закрытия соединения. Помимо этого, TCP является протоколом «наилучшего усилия», и он не дает никаких реальных гарантий того, что данные когда-либо действительно достигнут места назначения (в отличие от того, что, как кажется, некоторые считают), он просто старается изо всех сил доставить их в правильном порядке и как можно скорее.

0 голосов
/ 13 мая 2009

TCP обеспечивает только доставку с максимальным усилием, поэтому действие, когда все байты покидают компьютер A, асинхронно, поскольку все они получены на компьютере B. Стек протокола TCP / IP, конечно, знает, но я не знать любой способ опроса стека TCP, чтобы выяснить, все ли отправленные сообщения были подтверждены.

Самым простым способом решения вопроса является на уровне приложения . Откройте второй сокет TCP, чтобы действовать в качестве обратного канала, и пусть удаленный партнер отправит вам подтверждение того, что он получил нужную вам информацию. Это будет стоить вдвое, но будет полностью переносимым и сэкономит вам часы программирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...