Как закрыть Socket правильно?
От: SanyaVB  
Дата: 03.02.21 07:15
Оценка:
Привет всем!

Использую класс System.Net.Sockets.TcpClient.

Закрываю соединение как-то так:

    var socket = client.Client;
    try { socket.Shutdown(SocketShutdown.Both); }
    finally { socket.Close(); }
    client.Close();
    socket.Dispose();
    client.Dispose();
    client = null;


В результате соединение рвется, во всяком случае сервер фиксирует отключение (сервер и клиент находятся на одном ПК), но есть НО.

Пишу команду netstat и вижу, что соединение существует, но только в статусе TIME_WAIT
С одной стороны: НУ И ПУСТЬ! СО ВРЕМЕНЕМ ЗАКРОЕТСЯ! а с другой стороны, порт то занят + осадок на душе остаётся)))
Подскажите, кто с такой проблемой сталкивался, как решали?
Re: Как закрыть Socket правильно?
От: Xander Zerge Россия www.zerge.com
Дата: 03.02.21 07:54
Оценка: 28 (3) +2
Здравствуйте, SanyaVB, Вы писали:

SVB>Пишу команду netstat и вижу, что соединение существует, но только в статусе TIME_WAIT

SVB>С одной стороны: НУ И ПУСТЬ! СО ВРЕМЕНЕМ ЗАКРОЕТСЯ! а с другой стороны, порт то занят + осадок на душе остаётся)))
SVB>Подскажите, кто с такой проблемой сталкивался, как решали?

Это не проблема, а фича. Если сразу освободить порт и переподключиться, есть риск получить соединение с тем же портом и получить какой-нибудь застрявший пакет со старого соединения.
Но если очень хочется, то есть опция System.Net.Sockets.LingerOption, которая определяет сколько времени сокет провисит в TIME_WAIT, и эту опцию нужно записать в свойство Socket.LingerState.
Серёжа Новиков,
программист
Re: Как закрыть Socket правильно?
От: _NN_ www.nemerleweb.com
Дата: 03.02.21 08:40
Оценка:
Здравствуйте, SanyaVB, Вы писали:

SVB>Привет всем!


SVB>Использую класс System.Net.Sockets.TcpClient.


SVB>Закрываю соединение как-то так:


SVB>
SVB>    var socket = client.Client;
SVB>    try { socket.Shutdown(SocketShutdown.Both); }
SVB>    finally { socket.Close(); }
SVB>    client.Close();
SVB>    socket.Dispose();
SVB>    client.Dispose();
SVB>    client = null;
SVB>


Неужели простого кода с using недостаточно ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Как закрыть Socket правильно?
От: SanyaVB  
Дата: 03.02.21 08:55
Оценка:
Здравствуйте, Xander Zerge, Вы писали:

XZ>Это не проблема, а фича. Если сразу освободить порт и переподключиться, есть риск получить соединение с тем же портом и получить какой-нибудь застрявший пакет со старого соединения.

ОГО! Спасибо! Не знал такого...

XZ>Но если очень хочется, то есть опция System.Net.Sockets.LingerOption, которая определяет сколько времени сокет провисит в TIME_WAIT, и эту опцию нужно записать в свойство Socket.LingerState.


client.LingerState = new LingerOption(true, 3);


TIME_WAIT все равно висит минуту.
Re: Как закрыть Socket правильно?
От: Pzz Россия https://github.com/alexpevzner
Дата: 03.02.21 09:57
Оценка: 8 (1)
Здравствуйте, SanyaVB, Вы писали:

SVB>Пишу команду netstat и вижу, что соединение существует, но только в статусе TIME_WAIT

SVB>С одной стороны: НУ И ПУСТЬ! СО ВРЕМЕНЕМ ЗАКРОЕТСЯ! а с другой стороны, порт то занят + осадок на душе остаётся)))

Это так и должно быть. TCP так устроен. Сокет на той стороне, которая первая сказала close(), остается на 40 секунд в состоянии TIME_WAIT.

Если у тебя клиент-серверное приложение, и протокол выбираешь ты, лучше определить протокол таким образом, чтобы соединение закрывали клиенты. У них таких соединений будет немного, а на стороне сервера может заметное количество накопиться.

Но есть еще одна вещь, которую ты не учитываешь. Закрытие сокета — операция, по умолчанию, блокирующаяся, и может занять какое-то время (в среднем полсекунды, но при неудачном раскладе и до десятков секунд может дойти).

Если для твоей задачи это критично, есть смысл об этом подумать.
Re: Как закрыть Socket правильно?
От: vlp  
Дата: 05.02.21 02:33
Оценка:
Здравствуйте, SanyaVB, Вы писали:

SVB>С одной стороны: НУ И ПУСТЬ! СО ВРЕМЕНЕМ ЗАКРОЕТСЯ! а с другой стороны, порт то занят + осадок на душе остаётся)))

в общем случае этого сделать нельзя и не нужно.
Есои волнует занятость порта и потенциалньые пробелмы с безопасностью не волнуют — SO_REUSEADDR в помощь

http://www.unixguide.net/network/socketfaq/4.5.shtml

если волнуют — https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.