Pagina 1 di 3 1 2 3 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 22
  1. #1
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    207

    [VB.NET] Problema con Socket

    Sono un profano per quanto riguarda la programmazione in rete, ma mi hanno dato un lavoro da fare e mi sono bloccato in un punto che ora vi spiego.

    Devo creare un listener che ascolta su una porta i messaggi che gli arrivano da un client (in futuro potrebbero essere più di uno) e mandare messaggi in risposta.

    Il client in questione è una postazione 3M Self Check System per fare il prestito automatico nelle biblioteche.

    Ho il client che mi manda i messaggi. Non so come sia programmato il client perché non ho i sorgenti.

    Per il listener mi sono affidato al codice di esempio che trovate qui http://msdn.microsoft.com/en-us/library/fx6588te.aspx opportunamente modificato nella parte che gestisce la ricezione di messaggi ed invia il messaggio corretto.

    Come vi ho detto, sono un profano ed utilizzando il codice così com'è succedeva che il client dava sempre errore di connessione: ho scoperto che il problema era dovuto alle righe

    handler.Shutdown(SocketShutdown.Both)
    handler.Close()

    che trovate scorrendo il codice.
    Commentate queste righe, il client da segni di vita e mostra la prima schermata che deve mostrare.

    I problemi nascono a questo punto: dal client devo inviare al listener un altro messaggio (il codice della tessera del lettore, il messaggio viene opportunamente formattato dal client). Al momento di farlo, al listener non arriva niente e il client rimane "appeso" salvo poi rinunciare all'invio del messaggio dando errore di "troppi tentativi".

    Inoltre accade questo: quando cerco di fermare il client, l'operazione è impossibile a meno che non fermo manualmente il listener (cosa che non deve accadere) e il client si ferma subito.

    Mi hanno un programma di test (senza i codici sorgente) e con questo programma tutto funziona, mentre io non riesco a far funzionare il mio codice.

    Sono bloccato in questo punto. Come mi suggerite di procedere?
    Grazie.

  2. #2
    Inserisci il linguaggio..

    Ciao

  3. #3
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    207
    Originariamente inviato da MdE2005
    Inserisci il linguaggio..

    Ciao
    L'ho inserito nel titolo del topic, anche se ai miei fini cambia poco: qualsiasi cosa in .NET va bene e l'argomento è un po' trasversale e non tanto specifico di un linguaggio. Una sezione però dovevo sceglierla e ho scelto quella che include il linguaggio che utilizzo.

  4. #4
    se in futuro ci devono essere + client ti consigli un'architettura multithread formata così:

    Thread principale: accetta le connessioni e crea le istanze di una classe (Client)

    Threads secondari: Saranno i thrads che fara partire il costruttore della classe Client, ovviamente nel metodo del Thread usi un socket.Poll per bloccare il thread fino a quando non ci sono dati in arrivo.


    codice:
     public class Principale
        {
            private TcpListener listener;
            //metodo che accetta le connessioni e genera i clients
            public Principale()
            {
                this.listener = new TcpListener(IPAddress.Any, porta);
                this.listener.Start();
                 while (true)
                 {
                        Socket socketForClient = this.listener.AcceptSocket(); //resta bloccato fino a quando non si connette un client e ritorna il socket di quel client
                         new Client(socketForClient);
                 }
            }
    }
    l'accettazione dei socket avviene in un ciclo while infinito, volendo invece del true nel While ci puoi mettere una tua condizione.
    Non ci resta che far partire il thread del Client:

    codice:
     public class Client
        {
            private Socket socket;
            private Thread threadClient
            //metodo che lancia il Thread
            public Client(Socket socket)
            {
                  this.socket = socket;
                  this.threadClient = new Thread(new ThreadStart(this.leggiDati));
                  this.threadClient.IsBackground = true;
                  this.threadClient.Start();
            }
            public void leggiDati(){
               while(this.socket.Connected){
                     byte[] buf = new byte[1024];
                     if (this.socket.Poll(-1, SelectMode.SelectRead))
                     {
                           this.socket.Receive(buf)//legge i dati che sono arrivati e li inserisce nel buffer
                           String strRicevuta = Encoding.UTF8.GetString(buf);//converte i byte ricevuti in una stringa
                           /*operazioni da svolgere*/
    
                      }else{
                         break;
                      }
               }
            }
    }

    + o - lo farei così, devi gestire le eccezioni, visto che sono risorse non gestite.

  5. #5
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    207
    Grazie. Cerco di analizzare e mettere in pratica il codice che hai scritto.
    Spero che mi consenta di risolvere i gravi problemi che ho descritto (blocco del client finché il listener non viene fermato, impossibilità di gestire più di un messaggio verso uno stesso client).

  6. #6
    questo tipo di approccio risolve tutti i problemi ed è anche molto performante, rendendo i client indipendenti tra di loro

  7. #7
    il link msdn ke hai posto utilizza i socket asincroni, personalmente li sconsiglio, se proprio si vuole creare un server asincrono usa i socket basati sugli eventi SocketAsyncEventArgs molto + performanti e riutilizzabili in modo da ocupare meno risorse.
    L'approccio che ti ho scritto io è più semplice

  8. #8
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    207
    Ho fatto una rapida prova, gestendo per ora i messaggi in modo statico... e funziona!!
    Grazie!

    Ma sai dirmi cos'è che non andava nel codice che ho trovato che non mi faceva andare oltre lo scambio del primo messaggio?

  9. #9
    Ho dato uno sguardo veloce al codice sembra ok, solo nel metodo ReadCallback c'è questa parte di codice può farti quel difetto, che in realtà non è un difetto, è una cosa voluta;

    codice:
                if (content.IndexOf("<EOF>") > -1) {
                    // All the data has been read from the 
                    // client. Display it on the console.
                    Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
                        content.Length, content );
                    // Echo the data back to the client.
                    Send(handler, content);
                } else {
                    // Not all data received. Get more.
                    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReadCallback), state);
                }
    praticamente questa parte di codice fa questo:

    se la stringa letta contiente un End of File stampa nella console il numero di byte letti e la stringa letta e la reinvia al Client quando il trasferimento al client è terminato viene richiamato un altro metodo che si chiama SendCallBack (andremo a vederlo dopo).
    Invece se la stringa non contiente l'eof continua a ricevere dei dati.

    il metodo Send CallBack:

    codice:
        private static void SendCallback(IAsyncResult ar) {
            try {
                // Retrieve the socket from the state object.
                Socket handler = (Socket) ar.AsyncState;
    
                // Complete sending the data to the remote device.
                int bytesSent = handler.EndSend(ar);
                Console.WriteLine("Sent {0} bytes to client.", bytesSent);
    
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
    
            } catch (Exception e) {
                Console.WriteLine(e.ToString());
            }
        }
    qui il probema, invece di rimettere di ascoltare ancora il socket con un handler.BeginReceive(...), chiude la connessione del socket e non ricevi + niente.

    soluzioni:
    se il cliente invia un eof per ogni trasmissione allora puoi lasciare quella condizione altrimenti la elimini. Cmq se vuoi restare in Streaming il metodo beginReceive lo devi chiamare sempre:

    Eliminiamo il blocco else
    codice:
                if (content.IndexOf("<EOF>") > -1) {
                    // All the data has been read from the 
                    // client. Display it on the console.
                    Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
                        content.Length, content );
                    // Echo the data back to the client.
                    Send(handler, content);
                } 
                    // Not all data received. Get more.
                    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReadCallback), state);
    poi elimina la chiusura del socket dal blocco sendCallback
    codice:
        private static void SendCallback(IAsyncResult ar) {
            try {
                // Retrieve the socket from the state object.
                Socket handler = (Socket) ar.AsyncState;
                // Complete sending the data to the remote device.
                int bytesSent = handler.EndSend(ar);
                Console.WriteLine("Sent {0} bytes to client.", bytesSent);
            } catch (Exception e) {
                Console.WriteLine(e.ToString());
            }
        }


    così dovrebbe andare...ovviamente non l'ho provato!

  10. #10
    Mi sorge un dubbio:

    non so se quell'eof stia a significare la chiusura del socket da parte del client;
    cioè quando il client si disconnette invia al server 0 byte da leggere, che probabilmente è quell'eof.

    se è così il codice msdn va bene solo che devi gestire diversamente il SendCallback, perchè così quando decidi di inviare qualcosa al client dopo gli chiudi anche la connessione, quindi devi separare invio e chiusura in 2 metodi differenti.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.