Ваш код оборачивает асинхронный процесс в блок using
, поэтому, естественно, выполнение кода продолжается, достигает конца блока using
и удаляет сначала поток, а затем TcpClient - до того, как нижележащие сокеты завершатфизическая передача данных.Using
и Async
не всегда соответствуют друг другу, как вы видели.
Ваш await
регистрирует остаток метода как продолжение асинхронной операции, а затем возвращается кзвонящий сразу.Продолжение выполняется, как только WriteAsync возвращает.
Возможно, вы ожидали, что WriteAsync вернется только после успешной передачи всех байтов.Это кажется логичным, но не правильно.WriteAsync возвращается, когда записывает данные в поток, но это не означает, что данные вышли через TCPIP.Поток все еще будет использоваться с активностью сокета, продолжающейся, когда WriteAsync возвращает.
Поскольку ваше продолжение не содержит ничего, вы немедленно выходите из блока using
, и поток удаляется, пока он еще используется.
Так что я думаю, что с вашим клиентом или вашим потоком все в порядкеи промывка не поможет.Вы получаете именно то поведение, которое ожидается от кода, который вы написали, учитывая поведение вашего Echo server
.
. Вы можете прочитать сообщение в блоге Эрика Липперта о await async здесь .
Вы можете прочитать еще один вопрос SO, связанный с аналогичной проблемой здесь .
Если вы не контролируете Echo Server
, тогда у вас в основном есть два варианта.Вы можете отказаться от using
- вместо этого просто создайте экземпляр клиента и потока, а затем используйте их при некотором естественном наборе обстоятельств и только close
их, когда (где-то позже в вашем приложении) вы уверены, что с ними покончено,Естественно, вам понадобится какой-то способ определить, что вы сделали (или добраться до некоторой точки, где вы хотите закрыть их, независимо от того, были ли данные успешно получены где-то).
OTOH, если вы хотите сохранить using
block, тогда вы должны поместить некоторый код в свое продолжение для проверки на завершение, поэтому вы не закрываете поток для дальнейшей связи, как только WriteAsync передает данные сокету и запрашивает отключение сокета.,
Если вы отправляете очень маленькие сообщения и уверены, что знаете, сколько времени потребуется, чтобы они были отправлены или устарели, вы можете просто добавить руководство await Task.Delay()
- но это грязный подход, которыйв конечном итоге вызовет проблемы.
Или вы можете использовать метод, который не является асинхронным.Асинхронные методы полностью асинхронны, поэтому WriteAsync
будет вызывать или реализовывать асинхронные методы, такие как Stream.BeginWrite
, которые, конечно, возвращаются до завершения передачи.Не асинхронные методы, такие как Write()
, будут вызывать или реализовывать не асинхронные потоковые методы, такие как Stream.Write()
, которые возвращаются только после того, как сокет фактически отправил байт.Отсутствие проблем с сетью, это чаще всего означает, что ваши данные будут получены, даже если вы не делаете подтверждения на уровне приложения.См. Framework для потоков.
Метод Write блокируется до тех пор, пока не будет отправлено запрошенное количество байтов или не сгенерировано исключение SocketException.
КонечноЕсли у вас есть Echo server
, вы можете посмотреть, почему он перестает отображать данные, когда он больше не может обмениваться данными с вашим удаленным сетевым потоком.