- Come creare un semplice server TCP
senza utilizzare i socket -
|
|||
COSA SERVE PER QUESTO TUTORIAL | |||
Download | Chiedi sul FORUM | Glossario | cognizioni basiche di un qualsiasi linguaggio .Net | ||
Le classi per semplificare i socket: TcpClient, TcpListener e NetworkStream | |||
UN SERVER CON THREAD O CON I/O ASINCRONO Differenze tra l'uso di thread e chiamate asincrone. In questo tutorial ci occuperemo di come realizzare un semplice server echo, ovvero che reinvia al client ogni riga ricevuta dallo stesso. Il server dovrà essere in grado di gestire più client in parallelo e per fare ciò dimostreremo due diverse tecniche supportate dal framework .Net, la prima semplicemente consiste nel creare un thread per ogni richiesta, mentre la seconda si serve delle chiamate asincrone e quindi del pool di thread di sistema. Per prima cosa dovremo metterci in ascolto su una porta TCP, ci serviremo dunque della classe TcpListener (in System.Net.Sockets), che offre alcune semplificazioni rispetto all'uso della classe Socket grezza. 'Crea il socket per il server Dim listener As New TcpListener(IPAddress.Loopback, echoPort) 'Inizia ad ascoltare sul socket creato listener.Start()
I parametri del costruttore di TcpListener indicano l'indirizzo IP su
cui porsi in ascolto (in questo caso è stato scelto quello di loopback,
ovvero 127.0.0.1) e la porta, che può essere scelta a piacere tra quelle
non già occupate. Per mettersi in ascolto non si deve quindi far altro
che invocare il metodo Start. Do 'Si blocca in attesa di un client Dim clientSocket As TcpClient = listener.AcceptTcpClient() 'Avvia un nuovo thread per rispondere al client Dim clientManager As New Thread(AddressOf EchoServer) clientManager.Start(clientSocket) Loop
Si tratta sostanzialmente di chiamare sul TcpListener il metodo
AcceptTcpClient, che, essendo bloccante, interromperà il flusso del
programma fino alla ricezione di una connessione. Quando la connessione
è stabilita il flusso riprende creando un nuovo thread a cui viene
passato un riferimento al socket (oggetto TcpClient, altra astrazione di
un Socket) tramite cui comunicare con il client. In questo modo il ciclo
può ricominciare bloccandosi nuovamente su AcceptTcpClient. Do 'Effettua una chiamata asincrona per accettare un client: 'all'arrivo di un client la funzione SocketAccepted verrà 'chiamata listener.BeginAcceptTcpClient(AddressOf SocketAccepted, listener) 'Si pone in attesa su waitObject, che verrà sbloccato all'inizio 'di SocketAccepted SyncLock waitObject Monitor.Wait(waitObject) End SyncLock Loop In questo caso utilizziamo il metodo BeginAcceptClient che non è bloccante, ma quando una connessione in ingresso è pronta invoca il metodo passato come primo parametro, in questo caso SocketAccepted (che avrà accesso al secondo parametro, listener). Non essendo bloccante l'esecuzione continuerà ma si fermerà su Monitor.Wait su un oggetto globale, che verrà sbloccato all'interno di SocketAccepted facendo ricominciare il ciclo: Public Sub SocketAccepted(ByVal result As IAsyncResult) 'Sblocca la funzione in attesa così che possa mettersi in ascolto nuovamente 'per gestire un nuovo client SyncLock waitObject Monitor.Pulse(waitObject) End SyncLock 'Accetta la connessione in ingressa a la gestisce Dim listener As TcpListener = DirectCast(result.AsyncState, TcpListener) EchoServer(listener.EndAcceptTcpClient(result)) End Sub
Come detto il metodo SocketAcceped sblocca l'oggetto
waitObject e quindi
il ciclo, quindi accetta la connessione in ingresso tramite
EndAcceptTcpClient. Sub EchoServer(ByVal connection As TcpClient) 'Creiamo stream testuali per comunicare con il client Dim reader As New StreamReader(connection.GetStream(), noBomUTF8) Dim writer As New StreamWriter(connection.GetStream(), noBomUTF8) 'Ad ogni chiamata a WriteLine il messaggio viene inviato al client writer.AutoFlush = True 'Saluto iniziale con l'indirizzo IP del client writer.WriteLine("Welcome {0}", connection.Client.RemoteEndPoint.ToString) Dim inputLine As String = reader.ReadLine() 'Gestiamo l'input dell'utente e rispondiamo Do While inputLine <> "quit" writer.WriteLine(inputLine) inputLine = reader.ReadLine() Loop writer.WriteLine("Bye bye!") connection.Close() End Sub Non fa altro che creare due oggetti, uno per leggere e uno per scrivere su uno stream trattandoli come testuali. Per avere lo stream di comunicazione con il client basta invocare il metodo TcpClient.GetStream(), dopodiché si può agire come su un qualsiasi StreamReader/StreamWriter. Infine chiude la connessione.
UN SEMPLICE CLIENT Vediamo ora come si può creare un piccolo client per il server echo che abbiamo creato: Sub Test(ByVal output As Stream) Dim client As New TcpClient() client.Connect("localhost", echoPort) Dim writer As New StreamWriter(client.GetStream(), noBomUTF8) writer.WriteLine("time") writer.WriteLine("hello") writer.WriteLine("don't repeat!") writer.WriteLine("quit") writer.Flush() client.GetStream.CopyTo(output) client.Close() End Sub Non dobbiamo far altro che utilizzare nuovamente la classe TcpClient, questa volta però istanziandola direttamente e comunicando al metodo Connect indirizzo e porta del server. Quindi otteniamo lo stream per comunicare come visto poco fa e inviamo alcuni messaggi. Infine copiamo l'output su un altro stream (ad esempio potrebbe essere Console.Out) per visualizzare la risposta.
|
|||
<< INDIETRO | by VeNoM00 |