Обратите внимание в журнале Wireshark, что RST не приходит раньше, чем через две секунды после FIN. FIN представляет собой закрытие соединения удаленной конечной точкой. RST представляет собой ответ, который является следствием попытки записи в соединение. Этот ответ не возникает до первой попытки записи в соединение после его закрытия.
См., Например, этот ответ для одного примера обсуждения этого поведения для TCP.
Когда вы вызываете WriteAsync()
, все, что происходит, - это отправка байтов. Это передача байтов, которая представляет успешное завершение операции. TCP не предоставляет подтверждения, что байты были получены . Важно отметить, что успешное завершение распознается до ответа RST (действительно, часто даже до его отправки, хотя это вопрос времени и не имеет отношения к этому обсуждению).
Операция отправки предоставляет возможность сетевому уровню получать уведомление о разорванном соединении (то есть RST), но прибывает после того, как операция отправки была успешно завершена. Таким образом, при любой последующей операции отправки API теперь знает о разорванном соединении и может завершиться с ошибкой, чтобы код вашего приложения мог обнаружить проблему.
Другими словами, да ... поведение, которое вы видите это нормально. Вот почему каждый протокол уровня приложения должен включать семантику постепенного закрытия, обе конечные точки должны быть готовы к отказу от любой операции с сокетом, и нельзя делать никаких предположений о том, были ли отправленные данные действительно получены. Единственный способ узнать наверняка, что удаленная конечная точка получила, - это спросить ее и получить ответ.
В частности, обратите внимание, что хотя вы можете не ожидать, что удаленная конечная точка отправит какие-либо фактические данные, вы все равно должен читать из сокета, чтобы вы могли обнаружить изящное закрытие (т.е. завершение операции чтения с длиной 0 байт).
Если бы вы сделали это в приведенном выше примере кода, вы бы увидели, что закрытие сообщается немедленно, когда удаленная конечная точка закрыла сокет. Таким образом, ваш клиентский код мог бы получать более своевременное уведомление о закрытии. Это не будет окончательным уведомлением о состоянии error , поскольку, конечно, конечная точка может выключить сокет с причиной «отправки», продолжая получать данные. Но в вашем сценарии он предоставит важную информацию, учитывая ваши дополнительные знания о том, как на самом деле разработан протокол приложения.