Domanda

Sto cercando di usare Questa app server pre-made c # tftp server con il mio modulo Windows C #.Nell'esempio del server degli autori, che funziona alla grande, utilizza un'app console.Quando sto provando a porting il suo esempio della console nell'app della mia forma, non funziona (nessun errore, semplicemente non si connette) e credo che il mio problema sia nell'istruzione "Usando":

using (var server = new TftpServer())
{
    server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
    server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
    server.Start();
    Console.Read();
}
.

Non sono sicuro se capisco correttamente ma credo che i blocchi Console.Read() mantengano l'app dall'uscita.Se questo è il caso, come avrei implementato un equivalente con un'app form.Non riesco a prendere la testa per "usare".Scusa, sono nuovo a c #.

È stato utile?

Soluzione

I moduli di Windows rimarranno sempre aperti fino a quando non sono esplicitamente chiusi dall'utente. Hanno sempre una filettatura che legge la coda dei messaggi per l'ingresso dell'utente, quindi non usciranno allo stesso modo in cui verrà visualizzata un'applicazione console sfrenata. Nei moduli di Windows, dobbiamo preoccuparci un po 'di più sul multithreading e sulla concorrenza di quanto saremmo in app console. Prevale per lo più naturalmente, ma non sempre.

A causa di ciò, non è possibile utilizzare davvero un equivalente a Console.Read() per tenere l'esecuzione dell'esecuzione dello smaltimento using fino a quando l'utente lo richiede. Se lo hai fatto, la tua forma sarebbe semplicemente non rispondente.

Tuttavia, sei fortunato! Un blocco using in C # non è altro che zucchero sintattico per ricordare di chiamare IDisposable.Dispose() dopo aver finito con un oggetto. Quindi l'equivalente a questo in un progetto di moduli potrebbe immagazzinare l'oggetto server in un campo a livello di classe, quindi chiamare server.Dispose() On, ad esempio, un evento Button.Click. Questo è, ovviamente, solo un esempio. Potresti anche farlo su Form.Closing se si è sentito più appropriato.

alto livello, vuoi fare qualcosa del genere:

    .
  1. Dichiara un campo nella tua classe di classe TftpServer server;.
  2. Registra un evento Load e qualsiasi cosa sia necessaria per il tuo server per funzionare nel tuo costruttore.
  3. Apri il campo server nell'evento Form_Load.
  4. Utilizzare gli eventi del server come si vede così in forma durante la vita del Form. Potresti o non devi preoccuparti della concorrenza, ma è una questione per un'altra domanda.
  5. Chiama server.Dispose() nell'evento Dispose del modulo.
  6. in Essence,

    class main : Form
    {
        private TftpServer server;
    
        public main()
        {
            InitializeComponent();
    
            this.Load += main_Load;
    
            server = new TftpServer();
            server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
            server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
        }
    
        private void main_Load(object sender, EventArgs e)
        {
            server.Start();
        }
    
        private void server_OnReadRequest(/* I wasn't sure of the arguments here */)
        {
            // use the read request: give or fetch its data (depending on who defines "read")
        }
        private void server_OnWriteRequest(/* I wasn't sure of the arguments here */)
        {
            // use the write request: give or fetch its data (depending on who defines "write")
        }
    
        protected override void Dispose(bool disposing)
        {
            if (server != null) // since Dispose can be called multiple times
            {
                server.Dispose();
                server = null;
            }
        }
    }
    
    .

Altri suggerimenti

Il problema è che lo smaltimento del server è ciò che è chiuso.Tieni presente che l'uso è solo zucchero sintattico.I seguenti due blocchi di codice sono [praticamente] equivalenti:

var foo = new Foo();
try
{
   foo.Do();
}
finally
{
   foo.Dispose();
}
.


.
using (var foo = new Foo())
{
   foo.Do();
}
.

Stai bloccando il thread principale dall'uscita in un'app console, ma in un'app di moduli è diversa.Il problema non è necessario tenere il thread all'interno dell'utilizzo facendo una sorta di operazione di blocco.Sarebbe cattivo, e il comportamento bloccherebbe la tua app moduli.Il problema è che non vuoi usare usando.Si desidera nuovo quando si avvia il server, quindi in seguito, sull'uscita dell'applicazione o su un clic di arresto, lo smaltisce esplicitamente con smaltimento ().

In a console application your TftpServer instance is listening until the thread exits which is only after a key is pressed which is detected by Console.Read()

In your forms app that Console.Read() isn't waiting around and so the using block finishes and that causes your server instance to fall out of scope.

So you are not exactly misusing the using but rather the intended use is not helping you at all. Take a look at using the task parallel library to let some background tasks run asynchronously.

A small note that also doubles as an answer, you could use a using block here, you just put it in your main function:

...(make your form and stuff) 
using (var server = new TftpServer())
{
   server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
   server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
   server.Start();
   Application.Run(yourFormHere); //This blocks until the form is closed
}

Another option I forgot to mention is overriding Dispose in your Form. You probably want to do this. With this option you're guaranteed your server will be disposed (bar some event that would prevent it from being disposed either way [ie. being out of memory])

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