Domanda

Quando si utilizza Net.Sockets.TcpListener, qual è il modo migliore per gestire le connessioni in entrata (.AcceptSocket) in thread separati?

L'idea è di iniziare un nuovo thread quando viene accettata una nuova connessione in entrata, mentre tcplistener rimane disponibile per ulteriori connessioni in entrata (e per ogni nuova connessione in entrata viene creato un nuovo thread).Tutte le comunicazioni e le terminazioni con il client che ha originato la connessione verranno gestite nel thread.

È apprezzato l'esempio C# di codice VB.NET.

È stato utile?

Soluzione

Il codice che ho utilizzato è simile al seguente:

class Server
{
  private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false);

  public void Start()
  {
    TcpListener listener = new TcpListener(IPAddress.Any, 5555);
    listener.Start();

    while(true)
    {
      IAsyncResult result =  listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
      connectionWaitHandle.WaitOne(); // Wait until a client has begun handling an event
      connectionWaitHandle.Reset(); // Reset wait handle or the loop goes as fast as it can (after first request)
    }
  }


  private void HandleAsyncConnection(IAsyncResult result)
  {
    TcpListener listener = (TcpListener)result.AsyncState;
    TcpClient client = listener.EndAcceptTcpClient(result);
    connectionWaitHandle.Set(); //Inform the main thread this connection is now handled

    //... Use your TcpClient here

    client.Close();
  }
}

Altri suggerimenti

Credo che tu lo faccia allo stesso modo di qualsiasi altra operazione asincrona in .NET:chiami la versione BeginXxx del metodo, in questo caso BeginAcceptSocket.La richiamata verrà eseguita sul pool di thread.

I thread in pool generalmente scalano molto meglio dei thread per connessione:una volta superate alcune decine di connessioni, il sistema lavora molto più duramente nel passaggio da un thread all'altro che nel portare a termine il lavoro vero e proprio.Inoltre, ogni thread ha il proprio stack che in genere ha una dimensione di 1 MB (sebbene dipenda dai flag di collegamento) che deve essere trovato nello spazio degli indirizzi virtuali da 2 GB (sui sistemi a 32 bit);in pratica questo ti limita a meno di 1000 thread.

Non sono sicuro che il threadpool di .NET lo utilizzi attualmente, ma Windows ha un oggetto del kernel chiamato I/O Completion Port che assiste nell'I/O scalabile.È possibile associare thread a questo oggetto e ad esso possono essere associate richieste di I/O (inclusa l'accettazione di connessioni in entrata).Quando un I/O viene completato (ad es.arriva una connessione) Windows rilascerà un thread in attesa, ma solo se il numero di thread attualmente eseguibili (non bloccati per qualche altro motivo) è inferiore al limite di scalabilità configurato per la porta di completamento.In genere lo imposti su un piccolo multiplo del numero di core.

Vorrei suggerire un approccio diverso:Il mio suggerimento utilizza solo due thread.* un thread controlla le connessioni in entrata.* Quando viene aperta una nuova connessione, queste informazioni vengono scritte in una struttura dati condivisa che contiene tutte le connessioni aperte correnti.* Il 2° thread enumera la struttura dei dati e per ogni connessione aperta riceve i dati inviati e invia le risposte.

Questa soluzione è più scalabile dal punto di vista dei thread e, se implementata correttamente, dovrebbe avere prestazioni migliori rispetto all'apertura di un nuovo thread per connessione aperta.

C'è un ottimo esempio nel ricettario O'Reilly C# 3.0.È possibile scaricare la fonte di accompagnamento da http://examples.oreilly.com/9780596516109/CSharp3_0CookbookCodeRTM.zip

Vorrei utilizzare un threadpool, in questo modo non dovrai iniziare un nuovo thread ogni volta (poiché è piuttosto costoso).Inoltre, non aspetterei all'infinito ulteriori connessioni, poiché i client potrebbero non chiudere le loro connessioni.Come pensi di instradare il client allo stesso thread ogni volta?

Mi spiace, non ho il campione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top