Я не совсем знаком с C #, но недавно я выполнял аналогичную работу на Java и обнаружил три вещи.
Во-первых, вам необходимо закрыть соединения, даже после возникновения ошибок.Это может немного запутать, поскольку (по крайней мере, в Java) некоторые вызовы для очистки после себя могут генерировать исключения.
Во-вторых, это явное закрытие соединений позволяет сборщику мусора лучше выполнять свою работу.Однако вы на самом деле не контролируете, когда работает GC, поэтому вы не можете ожидать, что соединение будет очищено и сокет сразу же снова будет готов к использованию.Если вы немедленно попытаетесь открыть соединение, сокет может быть еще не готов.
В-третьих, операционная система часто участвует в управлении сетевыми подключениями и сетевыми ресурсами.То есть, если вы и ваша среда освободили и очистили ресурс, это еще не значит, что операционная система сделала (пере) сделала его доступным.