Oppure

Loading
17/10/12 17:54
Roby94
Salve, ho dovuto fare una piccola divergenza dai mio calssico sviluppo PHP per creare un server da utilizzare con i websocket di HTML5, lo sviluppo sembra andare bene avrei solo un piccolo problema quando cerco di fermare il server:
//avvio[...]//
        static void start()
        {
            if (serverActive == false)
            {
                try
                {
                    server.Start();
                    listenerThread = new Thread(new ThreadStart(listener));
                    listenerThread.Start();
                    serverActive = true;
                    Console.WriteLine("Il server è stato avviato.");
                }
                catch
                {
                    Console.WriteLine("Errore nell' avvio del server.");
                }
            }
            else Console.WriteLine("Il server è gia avviato.");
        }

        static void stop()
        {
            if (serverActive == true)
            {
                foreach (Client c in clients)
                {
                    try
                    {
                        c.Send("Il server si sta spegnendo. Arrivederci!");
                        c.client.Close();
                    }
                    catch { }
                }
                clients.Clear();
                listenerActive = false;
                listenerThread.Abort();//L'errore sta qua
                server.Stop();
                serverActive = false;
                Console.WriteLine("Il server è stato arrestato.");
            }
            else Console.WriteLine("Il server non è in esecuzione.");
        }

        static void listener()
        {
            listenerActive = true;
            while (listenerActive)
            {
                Socket client = server.AcceptSocket();
                if (clients.Count < 2)
                {
                    clients.Add(new Client(client));
                    Console.WriteLine("Utenti connessi: " + clients.Count);
                }
                else
                {
                    client.Send(ascii.GetBytes("Server Pieno!"));
                    Console.WriteLine(client.RemoteEndPoint.ToString() + " connessione rifiutata per limite utenti");
                    client.Close();
                }
                Thread.Sleep(10);
            }
        }
//Classe Client[...]//

Quando eseguo il metodo stop l'applicazione va in blocco nel punto che ho segnato, me ne accorgo dal fatto che il messaggio di conferma dell' arresto del server non viene stampato. Sono nuovo dei thread e credo che la mancanza di esperienza mi penalizzi un po, ho provato anche a interrompere il ciclo while ma sembra che esso continui ad oltranza probabilemnte perche si trova in un thread separato. Mi sapete aiutare?
P.S. Se ho fatto qualche errore madornale nello sviluppo del server me lo potreste segnalare, mi fareste un grnade piacere
Grazie in anticipo
aaa
17/10/12 18:40
tasx
Ciao puoi postare l'eccezione che ti viene scatenata?

Ciaociao :k:
aaa
17/10/12 18:50
Roby94
nessuna eccezione se uso Abort, è proprio quello il problema... sinceramente non capisco... se invece tolgo l'abort l'eccezione che viene generata da Socket client = server.AcceptSocket(); è SocketException e per l'appunto cerco di stoppare il while ed eliminare il thread per evitare che si verifichi. Se avete bisogno che posti tutto il codice ditemelo, ma credo che queste righe bastino.
aaa
17/10/12 19:41
tasx
Scusa ma il metodo start avvia un nuovo thread e poi? è dentro un altro ciclo? o c'è qualcosa che interrompe l'esecuzione?

Per la gestione delle variabili con accesso da più thread o le dichiari "volatile" o usi il sistema dei lock....
Teoricamente i thread non andrebbero "abortiti" (:rofl: :rofl: che termini...), per terminarli è sufficiente far terminare il metodo passato come threadstart...

Comunque ti consiglio di usare i Task che sono nuovi e molto più comodi....
aaa
17/10/12 20:07
Roby94
Allora con start avvio il server e creo un nuovo thread che controlla se vi sono connessioni al server attraverso un while(ho usato un nuovo thread appunto perche se no l'applicazione andava in loop con quel while(true) ed avevo bisogno che la console rimanesse utilizzabile per dare istruzioni al server)
        static void Main(string[] args)
        {
            start();
            readConsole();
        }

        static void readConsole() {
            String s = Console.ReadLine();
            switch(s) {
                case ">>start":
                    start();
                break;
                case ">>stop":
                    stop();
                break;
            }
            readConsole();
        }

Poi ho pensato; allo stop del server elimino il thread con abort (da qui il l'italianizzato "Abortire" :rofl:) in questo modo il metodo AcceptSocket non crea eccezioni... visto che non funzionava ho introdotto listenerActive in modo che cambiando il suo valore in false il ciclo si interrompesse per poi eliminare il thread ma anche cosi nada...
La mia idea di eliminare il thread veniva dal fatto che pensavo che al riavvio il server il creare un nuovo thread con lo stesso metodo comportasse dei conflitti.... è un idea sbagliata? Basta mettere il thread in pausa e dichiararne uno nuovo quando serve?
Comunque provo a vedere se trovo anche della documentazione su i Task che attualmente non conosco.
Grazie ;)
aaa
17/10/12 20:27
tasx
Allora secondo me ti conviene ripensare l'applicazione...

1) non usare tutti i metodi statici (mi hai fatto venire il mal di pancia ;) ;) ), crei un oggetto e poi nel Main gli dai un bel
new oggettoCheHaiCreato();


2) occhio al metodo readConsole(), non penso sia la soluzione migliore utilizzare la ricorsività... usa al massimo un while(anzi ti obbligo ad usarlo ;) )

3) nel thread principale(ovvero quello del Main) accetti i socket, una volta accettato il socket allora crei un nuovo thread passadogli il socket, o al massimo usi un task(sempre se usi .net 4.5) altrimenti nada, o forse anche 4.0, devo controllare).
// un esempio di task
void startTask()
{
   for(int i = 0; i < 100; i++)
   {
        new Task(() => {
                Console.WriteLine("task started...");
            }).start();
   }
}


si la soluzione con listeneractive ha senso però il thread è fermo su AcceptSocket quindi quando la setti a false
lui non termina e dunque ti salta l'eccezione, è per questo che ti consiglio di accettare i socket nel thread principale e poi assegnare un client ad ogni nuovo thread...

ciaociao :k:
aaa
17/10/12 21:15
Roby94
1)Ahahah tranqui è solo provvisorio, prima di creare le classi di argomenti che non conosco bene faccio sempre cosi, per organizzarle meglio ;) cosi quando le compongo parto da un codice gia finito
2) Essi speravo pure io di farlo in while solo che non ero sicuro di come ma adesso ho trovato basta metterlo su true, avevo paura di inviare 50000 readline :rofl: (non mi era mai capitato di dover tenere in acolto la console)
3) ok ma se metto l'accettazione dei socket sul main non rischio di bloccare l'appplicazione come ho menzionato prima?
grazie che mi hai spiegato il problema di listeneractive adesso ho capito ;)
Senti ma devo proprio creare un thread per ogni client o posso tenere come è ora
        class Client
        {
            public Socket client;
            protected EndPoint ip;

            public Client(Socket client)
            {
                this.client = client;
                this.ip = client.RemoteEndPoint;
                Console.WriteLine(this.ip.ToString() + " connesso al server");
                this.client.Send(ascii.GetBytes("Benvenuto!"));
                Thread listenerThread = new Thread(new ThreadStart(this.listener));
                listenerThread.Start();
            }

            protected void listener()
            {
                while (true)
                {
                    try
                    {
                        byte[] buffer = new byte[client.Available];
                        this.client.Receive(buffer);
                        Console.WriteLine("<" + this.ip + "> " + Encoding.Default.GetString(buffer));
                        foreach (Client c in clients)
                        {
                            c.Send("<" + this.ip + "> " + buffer.ToString());
                        }
                    }
                    catch { }
                    Thread.Sleep(10);
                }
            }

            public void Send(String message)
            {
                this.client.Send(ascii.GetBytes(message));
            }
        }

con la classe Client?

avevo scritto un messaggio molto completo ma poi il server mi ha tirato un brutto scherzo -_-
aaa