Não é possível vincular novamente um soquete a uma combinação de IP/porta existente

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

  •  09-06-2019
  •  | 
  •  

Pergunta

Saudações, estou tentando encontrar uma maneira de 'desvincular' um soquete de uma combinação específica de IP/Porta.Meu pseudocódigo fica assim:

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.

Neste ponto, o .Net me informa que já tenho um soquete vinculado a 127.0.0.1:4567, o que é tecnicamente verdade.Mas não importa qual código eu coloquei no destruidor da ClassA, ou quais funções eu chamo no soquete (tentei .Close() e .Disconnect(true)), o soquete permanece orgulhosamente vinculado a 127.0.0.1:4567.O que devo fazer para poder 'desvincular' o soquete?


EDITAR:Não estou confiando apenas na coleta de lixo (embora também tenha tentado essa abordagem).Tentei chamar a.Close() ou a.Disconnect() e só então instanciar aa;isso não resolve o problema.


EDITAR:Também tentei implementar IDisposable, mas o código nunca chegou lá sem que eu chamasse o método (o que era equivalente às tentativas anteriores, já que o método simplesmente tentaria .Close e .Disconnect).Deixe-me tentar ligar diretamente para .Dispose e entrar em contato com você.


EDIT (muitas edições, desculpas):Implementar IDisposable e chamar a.Dispose() de onde 'a' perde o escopo não funciona - minha implementação Dispose ainda precisa chamar .Close ou .Disconnect(true) (ou .Shutdown(Both)) mas nenhum deles é desvinculado a tomada.

Qualquer ajuda seria apreciada!

Foi útil?

Solução

(foi isso que finalmente fez tudo funcionar para mim)

Certifique-se de que CADA soquete ao qual o soquete em A se conecta tenha

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

definido ao ser iniciado.

Outras dicas

você não pode confiar na coleta de lixo do objeto em C # (presumo que você esteja usando c #, com base na marcação) se ele contém recursos como estar vinculado ao recurso de rede, como no seu exemplo, ou manter algum outro tipo de fluxo, um fluxo de arquivos seria um exemplo comum.

você tem que garantir a liberação dos recursos que o objeto contém, para que ele possa ser coletado como lixo.caso contrário, não será coletado como lixo, mas permanecerá vivo em algum lugar da memória.seu exemplo de pseudocódigo não fornece que você está liberando os recursos, apenas afirma que o objeto é (deveria ser) coletado como lixo.

O coletor de lixo não garante que o soquete será fechado.Para um exemplo completo, leia isto Exemplo MSDN.

O ponto principal é realmente ligar Socket.Close() O mais breve possível.Por exemplo, ClassA poderia implementar IDisponível e use assim:

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

O coletor de lixo executa o finalizador do objeto em algum momento indeterminado.Você pode implementar a interface IDisposable e chamar o método Dispose() antes que o objeto perca o escopo - ou deixar a instrução using fazer isso por você.

ver http://msdn.microsoft.com/en-us/library/system.idisposable.aspx e http://msdn.microsoft.com/en-us/library/yh598w02.aspx

editar:funciona bem para mim

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())
            {
            }
        }
    }
}

A melhor solução é tentar ligar o soquete novamente algumas vezes (2-3).Na primeira tentativa, se falhar, descobri que fechará adequadamente (e permanentemente) o soquete original.

HTH,

_NT

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top