Невозможно повторно привязать сокет к существующей комбинации IP/порта.

StackOverflow https://stackoverflow.com/questions/48356

  •  09-06-2019
  •  | 
  •  

Вопрос

Приветствую, я пытаюсь найти способ «отвязать» сокет от определенной комбинации IP/порта.Мой псевдокод выглядит так:

ClassA a = new ClassA(); //(class A  instantiates socket and binds it to 127.0.0.1:4567) 
//do something 
//...much later, a has been garbage-collected away.
ClassA aa = new ClassA(); //crash here.

В этот момент .Net сообщает мне, что у меня уже есть сокет, привязанный к 127.0.0.1:4567, что технически верно.Но независимо от того, какой код я вставляю в деструктор класса A или какие функции я вызываю в сокете (я пробовал .Close() и .Disconnect(true)), сокет остается гордо привязанным к 127.0.0.1:4567.Что мне сделать, чтобы иметь возможность «отвязать» сокет?


РЕДАКТИРОВАТЬ:Я не полагаюсь исключительно на сбор мусора (хотя я тоже пробовал этот подход).Я попробовал вызвать a.Close() или a.Disconnect() и только затем создать экземпляр aa;это не решает проблему.


РЕДАКТИРОВАТЬ:Я также пытался реализовать IDisposable, но код никогда не получался без моего вызова метода (что было эквивалентом предыдущих попыток, поскольку метод просто пробовал .Close и .Disconnect).Позвольте мне попробовать позвонить в .Dispose напрямую и перезвонить вам.


РЕДАКТИРОВАТЬ (много правок, извиняюсь):Реализация IDisposable и вызов a.Dispose(), из которого 'a' теряет область действия, не работает - моя реализация Dispose все равно должна вызывать либо .Close, либо .Disconnect(true) (или .Shutdown(Both)) но ни один из них не отвязывается розетка.

Любая помощь будет оценена по достоинству!

Это было полезно?

Решение

(это то, что наконец заставило меня все работать)

Убедитесь, что КАЖДАЯ розетка, к которой подключается розетка в A, имеет

socket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReuseAddress, true);

устанавливается при инициализации.

Другие советы

вы не можете полагаться на то, что объект будет собирать мусор в С# (я предполагаю, что вы используете С# на основе тегов), если он содержит ресурсы, такие как привязка к сетевому ресурсу, как в вашем примере, или содержит какой-либо другой тип потока, файловый поток будет распространенным примером.

вы должны убедиться, что ресурсы, хранящиеся в объекте, освобождены, чтобы его можно было собирать мусором.в противном случае он не будет собран мусором, а останется где-то в памяти.В вашем примере псевдокода не указано, что вы освобождаете ресурсы, вы просто утверждаете, что объект получает (должен получить) сбор мусора.

Сборщик мусора не гарантирует вам, что сокет когда-либо будет закрыт.Полный пример прочтите это пример MSDN.

Главное - позвонить Socket.Close() как можно скорее.Например, ClassA может реализовать IDодноразовый и используйте его следующим образом:

using (ClassA a = new ClassA()) 
{
    // code goes here
}
// 'a' is now disposed and the socket is closed

Сборщик мусора запускает финализатор объекта в неопределенное время.Вы можете реализовать интерфейс IDisposable и вызвать метод Dispose() до того, как объект потеряет область видимости, или позволить оператору using сделать это за вас.

видеть http://msdn.microsoft.com/en-us/library/system.idisposable.aspx и http://msdn.microsoft.com/en-us/library/yh598w02.aspx

редактировать:у меня отлично работает

using System;
using System.Net.Sockets;
using System.Net;

namespace ConsoleApplication1
{
    class Program
    {
        class ClassA : IDisposable
        {
            protected Socket s;
            public ClassA()
            {
                s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                s.Bind(new IPEndPoint(IPAddress.Any, 5678));
            }

            public void Dispose()
            {
                s.Close();
            }
        }

        static void Main(string[] args)
        {
            using(ClassA a=new ClassA()) {
            }
            using (ClassA b = new ClassA())
            {
            }
        }
    }
}

Лучшее решение — повторить попытку привязки сокета несколько раз (2–3).С первой попытки, если она потерпит неудачу, я обнаружил, что она правильно (и навсегда) закроет исходный сокет.

ХТХ,

_NT

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top