codice:
Imports System.Net.Sockets
Imports System.Text.ASCIIEncoding
Public Class frmMain
'Client: il client che si dovrà connettere al server
'FileSender: il client che ha il compito di trasferire i
' pacchetti di informazioni al server
Private Client, FileSender As TcpClient
'NetStream: lo stream su cui scrivere i dati di comunicazione
'NetFile: lo stream per inviare i dati da scrivere sul file
Private NetStream, NetFile As NetworkStream
'L'IP del server a cui connettersi
Private IP As String
'Invia un messaggio su uno stream di rete
Private Sub Send(ByVal Msg As String, ByVal Stream As NetworkStream)
'Se si può scrivere
If Stream.CanWrite Then
'Converte il messaggio in binario
Dim Bytes() As Byte = ASCII.GetBytes(Msg)
'E lo scrive sul network stream
Stream.Write(Bytes, 0, Bytes.Length)
End If
End Sub
'Ottiene un messaggio dallo stream di rete
Private Function GetMessage(ByVal Stream As NetworkStream) As String
'Se si può leggere
If Stream.CanRead Then
Dim Bytes(Client.ReceiveBufferSize) As Byte
Dim Msg As String
'Legge i bytes arrivati
Stream.Read(Bytes, 0, Bytes.Length)
'Li converte in una stringa leggibile
Msg = ASCII.GetString(Bytes)
'E restituisce la stringa
Return Msg.Normalize
Else
Return Nothing
End If
End Function
Private Sub btnConnetti_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnetti.Click
'Ottiene l'IP del server
IP = "127.0.0.1"
'Inizializza un nuovo client
Client = New TcpClient
'E tenta la connessione all'IP dato, sulla porta 25
stsStato.Text = "Connessione in corso..."
Try
Client.Connect(IP, 1989)
Catch SE As SocketException
MessageBox.Show("Impossibile stabilire una connessione!", _
Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Exit Sub
End Try
'Se la connessione è riuscita, ottiene lo
'stream condiviso di rete direttamente collegato con
'il networkstream del server
If Client.Connected Then
'Ora si è sicuri di essere connessi:
'sblocca i comandi per il trasferimento
NetStream = Client.GetStream
stsStato.Text = "Connessione riuscita ..."
End If
End Sub
Private Sub btnFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFile.Click
opFile.Filter = "Tutti i file|*.*"
If opFile.ShowDialog = Windows.Forms.DialogResult.OK Then
txtFile.Text = opFile.FileName
End If
End Sub
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
If Not IO.File.Exists(txtFile.Text) Then
MessageBox.Show("Il file non esiste ...", Me.Text, _
MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Exit Sub
End If
'Se si è connessi e si può scrivere
'sullo stream di rete...
If Client.Connected AndAlso NetStream.CanWrite Then
'Manda un messaggio al server, chiedendo
'conferma del trasferimento. Nel messaggio immette anche
'alcune informazioni riguardo il nome e la
'dimensione del file
Dim Msg As String = _
String.Format("ConfirmTransfer|{0}|{1}", txtFile.Text, _
FileLen(txtFile.Text))
'Invia il messaggio con la procedura scritta sopra
Send(Msg, NetStream)
'Attiva il timer per controllare i dati arrivati
tmrGetData.Start()
'Disattiva il pulsante per evitare più azioni
'contemporanee indesiderate
stsStato.Text = "In attesa di conferma dal server..."
End If
End Sub
Private Sub tmrGetData_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrGetData.Tick
If Client.Connected AndAlso Client.Available Then
'Ferma il timer mentre si eseguono le operazioni
tmrGetData.Stop()
'Legge il messaggio
Dim Msg As String = GetMessage(NetStream)
'Uso Contains per un semplice motivo. Quando si converte
'un array di bytes in una stringa, ci possono essere
'caratteri speciali successivi a questa, come ad esempio
'il NULL terminator (carattere 00), che ne compromettono
'la struttura.
If Msg.Contains("OK") Then
'Termina questa connessione e si connette
'alla porta deputata alla ricezione dei file
FileSender = New TcpClient
FileSender.Connect(IP, 1001)
If FileSender.Connected Then
'Ottiene lo stream associato a questa operaizone
NetFile = FileSender.GetStream
'E inizia la trasmissione dei dati
bgSendFile.RunWorkerAsync(txtFile.Text)
End If
End If
'Riprende il controllo dei dati
tmrGetData.Start()
End If
End Sub
Private Sub bgSendFile_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgSendFile.DoWork
'Ottiene il nome del file dall'argomento passato al metodo
'RunWorkerAsync nella procedura precedente
Dim FileName As String = e.Argument
'Crea un nuovo lettore del file a basso livello, così
'da poter ottenere bytes di informazione anziché caratteri
'come nello StreamReader
Dim Reader As New IO.FileStream(FileName, IO.FileMode.Open)
'Calcola la grandezza del file, per poter poi tenere
'l'utente al corrente della percentuale di completamento
Dim Size As Int64 = FileLen(FileName)
'Un blocco di bytes da 8192 posti. Il file viene spedito in
'"pacchettini" per evitare di sovraccaricare la connessione
Dim Bytes(8192) As Byte
'Se il file è più grande di 8KiB, lo divide
'in blocchi di dati da 8192 bytes
If Size > 8192 Then
For Block As Int64 = 0 To Size Step 8192
'Se i bytes rimanenti sono più di 8192,
'ne legge un blocco intero
If Size - Block >= 8192 Then
Reader.Read(Bytes, 0, 8192)
Else
'Altrimenti un blocco più piccolo
Reader.Read(Bytes, 0, Size - Block)
End If
'Scrive i dati prelevati sullo stream di rete,
'inviandoli così al server
NetFile.Write(Bytes, 0, 8192)
'Riporta la percentuale all'utente
bgSendFile.ReportProgress(Block * 100 / Size)
'Smette per 30ms, così da dare tempo dal
'server di poter processare i pacchetti uno per
'uno, evitando confusione
Threading.Thread.Sleep(100)
Next
Else
'Se il file è minore di 8KiB, lo invia tutto
'direttamente dal server
Reader.Read(Bytes, 0, Size)
NetFile.Write(Bytes, 0, Size)
End If
Reader.Close()
'Percentuale massima: lavoro terminato
bgSendFile.ReportProgress(100)
Threading.Thread.Sleep(100)
'Comunica la fine delle operazioni
'NetFile.Write(ASCII.GetBytes("END"), 0, 3)
stsStato.Text = "File inviato con successo ..."
End Sub
Private Sub bgSendFile_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgSendFile.ProgressChanged
prgProgress.Value = e.ProgressPercentage
End Sub
End Class