Поведение функции send(), когда ссылка обрывается в TCP-соединении

Ниже приведен сценарий:

A <-------------------------> B

Я использую неблокирующие сокеты как на A, так и на B (машины на базе Linux). A и B имеют TCP-соединение, и вдруг связь, соединяющая их, выходит из строя (ссылка может быть не прямой). Теперь, после того, как ссылка не работает, когда функция send() вызывается на стороне A для отправки некоторых данных на B, она успешно возвращается (т.е. возвращает количество байтов, которые должны быть отправлены).

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


person Sumit Trehan    schedule 26.06.2013    source источник
comment
Вы уверены, что используете TCP? Кроме того, что вы имеете в виду, что ссылка не работает? Вы закрываете розетку на B или отключаете ее?   -  person Magn3s1um    schedule 26.06.2013
comment
Я не закрываю сокет. Отключение может лучше описать сценарий   -  person Sumit Trehan    schedule 26.06.2013
comment
Я полагаю, что в данном случае важна семантика сценария. Если компьютер B все еще находится в сети, и вы отправляете ему пакеты, его сетевая карта, вероятно, отправляет подтверждение, даже если пакет не отправляется на прикладной уровень. Если он находится в сети, возможно, именно поэтому вы получаете успешное возвращаемое значение.   -  person Magn3s1um    schedule 26.06.2013
comment
На самом деле A и B в моем случае являются маршрутизаторами. Я выдаю команду закрытия порта в A, которая должна остановить все исходящие пакеты из A.   -  person Sumit Trehan    schedule 26.06.2013
comment
Итак, вы отправляете из А в Б и отключаете А, а А по-прежнему отправляет все пакеты? Возможно, он ждет, пока буфер не станет пустым, чтобы завершить работу/очистить выходной буфер.   -  person Magn3s1um    schedule 26.06.2013
comment
Какая операционная система? Влияет ли команда закрытия порта на состояния TCP соединений, использующих этот порт, или внутренний уровень IP пытается найти другой порт?   -  person jxh    schedule 26.06.2013
comment
@Magn3s1um Ваши комментарии не имеют смысла. Сетевые карты не отправляют ACK, это делают стеки TCP, а send() не ждет ACK перед возвратом. «Порт закрыт» ничего не знает о буферах. Вы, кажется, просто догадываетесь.   -  person user207421    schedule 27.06.2013


Ответы (1)


Это нормальное и ожидаемое поведение.

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

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

Первая причина, по которой он не знает, что данные не поступят, заключается в том, что к моменту завершения вызова send() данные еще не поступили в сеть: они были только поставлены в очередь в буфере.

Вторая причина, по которой он не знает, что данные не будут переданы, заключается в том, что он не может (по крайней мере, поначалу) определить разницу между каналом, который просто сбросил пакет, и пакетом, который может пройти, когда он пытается передать его. ретранслировать его, а не по кабелю, который был хорошо и по-настоящему обрезан. Даже при обрыве кабеля TCP некоторое время будет продолжать повторную передачу, надеясь, что либо (1) соединение вернется, либо (2) маршрутизаторы сойдутся на другом сетевом пути, который работает.

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

person Celada    schedule 26.06.2013
comment
Возвращает ли вызов send() успех, как только данные помещаются в очередь в буфере отправки TCP? - person Sumit Trehan; 29.06.2013
comment
Предположим, я не подключаю провод, означает ли это, что TCP всегда будет продолжать повторную передачу пакетов, если не получит подтверждение? Когда он действительно обнаружит сбой соединения? - person Sumit Trehan; 29.06.2013
comment
Да, send() возвращает успех, как только данные будут приняты ядром. Если вы никогда не переподключите провод, TCP в конечном итоге истечет (обычно через несколько минут), и дальнейшие операции с сокетом вернут ошибку тайм-аута. - person Celada; 29.06.2013
comment
Каков тайм-аут повторной передачи по умолчанию в TCP? Как часто он будет пытаться повторно передать потерянный пакет - person Sumit Trehan; 02.07.2013
comment
Есть ли ссылка, описывающая это поведение? - person Jer; 01.05.2020