Я думаю, что вы все делаете правильно:
Socket.Close должно освободить все управляемые и неуправляемые ресурсы, связанные с сокетом.
Но вы также пытались установить
socket = null;
А может (после этого) использовать
GC.Collect();
, чтобы вручную запустить сборщик мусора, утечка все еще присутствует после этого?
Другая идея: Как вы отслеживаете утечку ручки?ОС может хранить закрытое TCP-соединение в памяти в течение длительного времени (минут), это нормальное поведение.