Tag Archives: vb.net

[DotNet] Vérifier la disponibilité d’un port en écoute

dotnet microsoft

Nous vivons dans un monde surconnecté, c’est pourquoi la plupart des applications utilisent une architecture Client / Serveur afin de communiquer et transmettre des données.

Lorsqu’on développe une application Serveur qui va se mettre en écoute sur un ou plusieurs ports il est primordial de vérifier leur disponibilité.

En effet, sur une même machine il est impossible de mettre 2 applications en écoute sur le même port their website.

Voici la solution que j’utilise pour effectuer cette vérification de port listener.

[DotNet] Remplacer les caractères accentués et les caractères non imprimables

dotnet special character

La langue française est merveilleuse mais les caractères accentués peuvent vite devenir pénalisant dans le développement d’une application.

En effet, certains logiciels ne supportent pas ou mal l’encodage UTF8, et par conséquent les caractères spéciaux peuvent être mal interprétés.

Je vous propose donc une fonction DotNet qui remplacera les caractères accentués par le caractère équivalent non accentué.

[.Net] Classe HardwareId, identifiant d’ordinateur

hardwareid

Dans un de mes projets, je suis amené à identifier chaque machine sur laquelle mon logiciel est installé. Pour faire çà j’ai pensé à faire un identifiant spécifique à chaque ordinateur en me basant sur des propriétés matérielles.

La classe permet de générer un Hardware Id, c’est à dire un identifiant spécifique à chaque machine.
Cet identifiant peut ensuite être utilisé pour développer un système de gestion de licences ou bien pour nommer une instance de logiciel.

Cette classe se base sur les informations matérielles de la machine en les récupérant grâce à WMI.

Voici la classe HardwareId:

Imports System.Management
Imports System.Security.Cryptography
Imports System.Text
'Classe qui permet de générer un hardware id (pratique pour la gestion des licenses par exemple)
Public Class HardwareId
Private Shared _Hash() As Byte
#Region "Constructeur"
Shared Sub New()
Try
_Hash = GenerateHash(GenerateHardString())
Catch ex As Exception
Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace)
End Try
End Sub
#End Region
#Region "Fonctions de generation"
'Fonction qui genere un HardwareId sous forme de Md5
Public Shared Function GenerateMd5() As String
Dim ret As String = vbNullString
Try
ret = GenerateMd5(_Hash)
Catch ex As Exception
Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace)
End Try
Return ret
End Function
'Fonction qui genere un HardwareId sous forme d'entier
Public Shared Function GenerateInteger() As Integer
Dim ret As Integer = 0
Try
ret = GenerateMd5.GetHashCode
Catch ex As Exception
Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace)
End Try
Return ret
End Function
'Fonction qui genere un HardwareId sous forme de Guid
Public Shared Function GenerateGuid() As String
Dim ret As String = vbNullString
Try
ret = GenerateGuid(_Hash)
Catch ex As Exception
Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace)
End Try
Return ret
End Function
#End Region
#Region "Fonctions d'encryption"
'Fonction qui genere la chaine de base
Private Shared Function GenerateHardString() As String
Return "CPU >> " & GetCPUId() & vbCrLf & "BIOS >> " & GetBiosId() & vbCrLf & "MOTHERBOARD >> " & GetMotherboardId() & vbCrLf & "DISK >> " & GetDiskId() & vbCrLf & "GRAPHICS >> " & GetGraphicsId() & vbCrLf & "MACADDRESS >> " & GetMacId()
End Function
'Fonction qui génère le hash
Private Shared Function GenerateHash(ByVal str As String) As Byte()
Dim md5 As New MD5CryptoServiceProvider()
Dim enc As New ASCIIEncoding()
Return md5.ComputeHash(enc.GetBytes(str))
End Function
'Fonction qui formatte la sortie Guid
Private Shared Function GenerateGuid(ByVal b() As Byte) As String
Dim ret As String = vbNullString
Try
For i As Integer = 0 To b.Length - 1
Dim bb As Byte = b(i)
Dim n, n1, n2 As Integer
n = CInt(bb)
n1 = n And 15
n2 = (n >> 4) And 15
If n2 > 9 Then
ret &= Chr(n2 - 10 + Asc("A")).ToString
Else
ret &= n2.ToString
If n1 > 9 Then
ret &= Chr(n1 - 10 + Asc("A")).ToString()
Else
ret &= n1.ToString()
End If
If (((i + 1) <> b.Length) AndAlso ((i + 1) Mod 2 = 0)) Then
ret &= "-"
End If
End If
Next
Catch ex As Exception
Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace)
End Try
Return ret
End Function
'Fonction qui formatte la sortie Md5
Private Shared Function GenerateMd5(ByVal b() As Byte) As String
Dim ret As String = vbNullString
Try
Dim i As Integer
For i = 0 To b.Length - 1
ret &= b(i).ToString("x2")
Next i
Catch ex As Exception
Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace)
End Try
Return ret
End Function
#End Region
#Region "Recupération d'informations système"
'Fonction qui récupère les informations WMI
Private Shared Function GetWMI(ByVal wmiClass As String, ByVal wmiProperty As String, Optional ByVal wmiMustBeTrue As String = vbNullString) As String
Dim ret As String = vbNullString
Try
Dim mc As New ManagementClass(wmiClass)
Dim moc As ManagementObjectCollection = mc.GetInstances
For Each mo As ManagementObject In moc
Dim cont As Boolean = True
If wmiMustBeTrue <> vbNullString Then
If mo(wmiMustBeTrue) Is Nothing Or Trim(mo(wmiMustBeTrue).ToString.ToLower) <> "true" Then
cont = False
End If
End If
If cont Then
If ret = vbNullString Then
Try
If mo(wmiProperty) IsNot Nothing Then
ret = mo(wmiProperty).ToString()
Exit For
End If
Catch ex As Exception
End Try
End If
End If
Next
Catch ex As Exception
Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace)
End Try
Return ret
End Function
'Fonction qui retourne le numero de serie en fonctions de infos wmi recuperees
Private Shared Function GetSerial(ByVal wmiClass As String, ByVal wmiProperties() As String, ByVal stopAfterMatch As Boolean, Optional ByVal wmiMustBeTrue As String = vbNullString) As String
Dim ret As String = vbNullString
Try
For i As Integer = 0 To wmiProperties.Length - 1
Try
ret &= GetWMI(wmiClass, wmiProperties(i), wmiMustBeTrue)
If stopAfterMatch AndAlso ret <> vbNullString Then
Exit For
End If
Catch ex As Exception
End Try
Next
Catch ex As Exception
Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace)
End Try
Return ret
End Function
'Fonction qui retourne le CPU Id
Private Shared Function GetCPUId() As String
Return GetSerial("Win32_Processor", {"UniqueId", "Name", "Manufacturer", "MaxClockSpeed"}, True)
End Function
'Fonction qui retourne le Bios Id
Private Shared Function GetBiosId() As String
Return GetSerial("Win32_BIOS", {"Manufacturer", "SMBIOSBIOSVersion", "IdentificationCode", "SerialNumber", "ReleaseDate", "Version"}, False)
End Function
'Fonction qui retourne le Disk Id
Private Shared Function GetDiskId() As String
Return GetSerial("Win32_DiskDrive", {"Model", "Manufacturer", "Signature", "TotalHeads"}, False)
End Function
'Fonction qui retourne le Motherboard Id
Private Shared Function GetMotherboardId() As String
Return GetSerial("Win32_BaseBoard", {"Model", "Manufacturer", "Name", "SerialNumber"}, False)
End Function
'Fonction qui retourne le Graphics Id
Private Shared Function GetGraphicsId() As String
Return GetSerial("Win32_VideoController", {"DriverVersion", "Name"}, False)
End Function
'Fonction qui retourne l'addresse mac de la premiere carte reseau active
Private Shared Function GetMacId() As String
Return GetSerial("Win32_NetworkAdapterConfiguration", {"MACAddress"}, False, "IPEnabled")
End Function
#End Region
End Class

Pour utilise la classe HardwareId, il suffit de l’exécuter comme cela:

'Exemple d'utilisation:
Dim k As String = HardwareId.GenerateMd5
Console.WriteLine(k)
k = HardwareId.GenerateGuid
Console.WriteLine(k)
k = HardwareId.GenerateInteger.ToString
Console.WriteLine(k)

Vous pouvez télécharger la solution HardwareId Projet

[VB.Net] Générateur de mots

Pour la réalisation d’un nouvel outil de sécurité j’ai dû généré un dictionnaire de mots allant de 3 à 8 lettres.
Pour faire çà, j’ai donc développé la classe suivante:

'Exemple: Fonction qui génère les fichiers de words de 5 lettres
Private Sub Generator()
Call WordGenerator.Start(5)
Dim aLine As String = WordGenerator.GetString()
Dim tmp As New List(Of String)
While aLine IsNot Nothing
tmp.Add(aLine)
FileCounter += 1
If FileCounter = FileMax Then
Dim sw As New StreamWriter(Path.Combine("files", Environment.TickCount.ToString), False, System.Text.Encoding.UTF8)
For i As Integer = 0 To tmp.Count - 1
sw.WriteLine(tmp(i))
Next
sw.Close()
tmp.Clear()
FileCounter = 0
End If
aLine = WordGenerator.GetString()
End While
End Sub
'Classe qui génère des words
Public Class WordGenerator
Private Const _charStart As Integer = 33 'Code ASCII de la premiere lettre
Private Const _charEnd As Integer = 126 'Code ASCII de la dernière lettre
Public Shared Started As Boolean = False
Private Shared Arr() As Integer
Public Shared Sub Start(ByVal num As Integer)
ReDim Arr(num - 1)
For i As Integer = 0 To num - 1
Arr(i) = _charStart
Next
Started = True
End Sub
Public Shared Function GetString(Optional ByVal idx As Integer = 0) As String
Dim ret As String = Nothing
If Started Then
Arr(idx) = Arr(idx) + 1
If Arr(idx) > _charEnd Then
Arr(idx) = _charStart
If idx + 1 < Arr.Length Then
ret = GetString(idx + 1)
End If
Else
For i As Integer = 0 To Arr.Length - 1
ret &= Chr(Arr(i))
Next
End If
End If
Return ret
End Function
End Class

Vous générerez rapidement plusieurs Giga de mots uniques. Par exemple, pour 5 lettres, vous génèrerez 10000 millions de mots uniques

 

Résultat du concours CodinGame ASCII

Pour rigoler j’ai essayé de faire l’épreuve du CodinGame sur l’art ASCII.

Voici le code que j’ai fait en une vingtaine de minutes:

Imports System.IO
Module Module1
Sub Main(ByVal args() As String)
Dim s As New Stopwatch
s.Start()
If args.Length > 0 Then
If File.Exists(args(0)) Then
Dim lines() As String = File.ReadAllLines(args(0))
If lines.Count >= 4 Then
Dim largeur As Integer = CInt(lines(0))
'Dim hauteur As Integer = CInt(lines(1))
Dim mot As String = Trim(lines(2))
Dim linesParse As New List(Of String)
For i As Integer = 3 To lines.Count - 1
linesParse.Add(lines(i))
Next
Call AsciiLetter.SetLetters(largeur, linesParse)
Console.WriteLine(AsciiLetter.GetText(mot))
End If
End If
End If
s.Stop()
Console.WriteLine(s.ElapsedMilliseconds)
Console.ReadLine()
End Sub
Public Class AsciiLetter
Public Shared Letters(26) As List(Of String)
Public Shared Sub SetLetters(ByVal l As Integer, ByVal lines As List(Of String))
For i As Integer = 0 To lines.Count - 1
Dim line As String = lines(i)
Dim pos As Integer = 0
For j As Integer = 0 To 26
If i = 0 Then
Letters(j) = New List(Of String)
End If
Letters(j).Add(Mid(line, 1 + (j * l), l))
Next
Next
End Sub
Public Shared Function GetText(ByVal s As String) As String
Dim h As Integer = Letters(26).Count
Dim l As New List(Of List(Of String))
s = s.ToUpper
For i As Integer = 0 To s.Length - 1
Dim code As Integer = Asc(s(i)) - 65
If code >= 0 AndAlso code <= 25 Then
l.Add(Letters(code))
Else
l.Add(Letters(26))
End If
Next
Dim ret As String = vbNullString
For i As Integer = 0 To h - 1
For j As Integer = 0 To l.Count - 1
ret &= l(j)(i)
Next
If i < h - 1 Then ret &= vbCrLf
Next
Return ret
End Function
End Class
End Module

La solution dotnet est téléchargeable ici CodinGame ASCII.

[.Net] Serveur TCP Asynchrone et Client Tcp Asynchrone

J’utilise énormément les deux classes suivantes qui permettent d’instancier en asynchrone des serveurs TCP ou des clients TCP.

La classe ASyncTcpServer m’a permis ainsi de faire un serveur Web, un serveur FTP, un serveur de données et tout cela de manière asynchrone.

La classe ASyncTcpClient quant à elle permet de se connecter à des serveurs TCP divers et variés.

Je tiens à préciser que j’ai juste convertit ces classes en Vb.Net et qu’elles ont été développées à l’origine par Rob Davey.

Imports System.Net.Sockets
Imports System.Net
Imports System.Text
Imports System.Linq
Imports System.Threading
 
Module AsyncTcp
 
    ''' <summary>
    ''' An Asynchronous TCP Server that makes use of system managed threads
    ''' and callbacks to stop the server ever locking up.
    ''' </summary>
    Public Class AsyncTcpServer
 
#Region "Properties"
        Private TcpListener As TcpListener
        Private Clients As New List(Of Client)
 
        ''' <summary>
        ''' The encoding to use when sending / receiving strings.
        ''' </summary>
        Public Property Encoding As Encoding
 
        ''' <summary>
        ''' The data received.
        ''' </summary>
        Public Event DataReceived(ByRef Data() As Byte, ByRef DataLength As Integer, ByRef RemoteIP As String)
 
        ''' <summary>
        ''' An enumerable collection of all the currently connected tcp clients
        ''' </summary>
        Public ReadOnly Property TcpClients As IEnumerable(Of TcpClient)
            Get
                Return From x In Clients Select x.TcpClient
            End Get
        End Property
#End Region
 
#Region "Constructeurs"
        ''' <summary>
        ''' Constructor for a new server using an IPAddress and Port
        ''' </summary>
        ''' <param name="localaddr">The Local IP Address for the server.</param>
        ''' <param name="port">The port for the server.</param>
        Public Sub New(ByVal localaddr As IPAddress, ByVal port As Integer)
            Me.New()
            TcpListener = New TcpListener(localaddr, port)
        End Sub
 
        ''' <summary>
        ''' Constructor for a new server using an end point
        ''' </summary>
        ''' <param name="localEP">The local end point for the server.</param>
        Public Sub New(ByVal localEP As IPEndPoint)
            Me.New()
            TcpListener = New TcpListener(localEP)
        End Sub
 
        ''' <summary>
        ''' Private constructor for the common constructor operations.
        ''' </summary>
        Private Sub New()
            Me.Encoding = Encoding.Default
            Me.Clients = New List(Of Client)
        End Sub
#End Region
 
#Region "Start / Stop"
        ''' <summary>
        ''' Starts the TCP Server listening for new clients.
        ''' </summary>
        Public Sub Start()
            Me.TcpListener.Start()
            Me.TcpListener.BeginAcceptTcpClient(AddressOf AcceptTcpClientCallback, Nothing)
        End Sub
 
        ''' <summary>
        ''' Stops the TCP Server listening for new clients and disconnects
        ''' any currently connected clients.
        ''' </summary>
        Public Sub [Stop]()
            Me.TcpListener.Stop()
            SyncLock Me.Clients
                For Each c As Client In Me.Clients
                    c.TcpClient.Client.Disconnect(False)
                Next
                Me.Clients.Clear()
            End SyncLock
        End Sub
#End Region
 
#Region "Write"
        ''' <summary>
        ''' Writes a string to a given TCP Client
        ''' </summary>
        ''' <param name="tcpClient">The client to write to</param>
        ''' <param name="data">The string to send.</param>
        Public Sub Write(ByVal tcpclient As TcpClient, ByVal data As String)
            Dim bytes() As Byte = Me.Encoding.GetBytes(data)
            Write(tcpclient, bytes)
        End Sub
 
        ''' <summary>
        ''' Writes a string to all clients connected.
        ''' </summary>
        ''' <param name="data">The string to send.</param>
        Public Sub Write(ByVal data As String)
            For Each c As Client In Me.Clients
                Write(c.TcpClient, data)
            Next
        End Sub
 
        ''' <summary>
        ''' Writes a byte array to all clients connected.
        ''' </summary>
        ''' <param name="bytes">The bytes to send.</param>
        Public Sub Write(ByVal bytes() As Byte)
            For Each c As Client In Me.Clients
                Write(c.TcpClient, bytes)
            Next
        End Sub
 
        ''' <summary>
        ''' Writes a byte array to a given TCP Client
        ''' </summary>
        ''' <param name="tcpClient">The client to write to</param>
        ''' <param name="bytes">The bytes to send</param>
        Public Sub Write(ByVal tcpClient As TcpClient, ByVal bytes() As Byte)
            Dim networkStream As NetworkStream = tcpClient.GetStream()
            networkStream.BeginWrite(bytes, 0, bytes.Length, AddressOf WriteCallback, tcpClient)
        End Sub
 
        ''' <summary>
        ''' Callback for the write opertaion.
        ''' </summary>
        ''' <param name="result">The async result object</param>
        Private Sub WriteCallback(ByVal result As IAsyncResult)
            Dim tcpClient As TcpClient = CType(result.AsyncState, TcpClient)
            Dim networkStream As NetworkStream = tcpClient.GetStream()
            networkStream.EndWrite(result)
        End Sub
#End Region
 
        ''' <summary>
        ''' Callback for the accept tcp client opertaion.
        ''' </summary>
        ''' <param name="result">The async result object</param>
        Private Sub AcceptTcpClientCallback(ByVal result As IAsyncResult)
            Dim tcpClient As TcpClient = TcpListener.EndAcceptTcpClient(result)
            Dim buffer(tcpClient.ReceiveBufferSize) As Byte
            Dim client As New Client(tcpClient, buffer)
            SyncLock Me.Clients
                Me.Clients.Add(client)
            End SyncLock
            Dim networkStream As NetworkStream = client.NetworkStream
            networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, AddressOf ReadCallback, client)
            TcpListener.BeginAcceptTcpClient(AddressOf AcceptTcpClientCallback, Nothing)
        End Sub
 
        ''' <summary>
        ''' Callback for the read opertaion.
        ''' </summary>
        ''' <param name="result">The async result object</param>
        Private Sub ReadCallback(ByVal result As IAsyncResult)
            Dim client As Client = CType(result.AsyncState, Client)
            If client Is Nothing Then Exit Sub
            Try
                Dim networkStream As NetworkStream = client.NetworkStream
                Dim read As Integer = networkStream.EndRead(result)
 
                If read = 0 Then
                    SyncLock Me.Clients
                        Me.Clients.Remove(client)
                        Exit Sub
                    End SyncLock
                End If
                Dim data As String = Me.Encoding.GetString(client.Buffer, 0, read)
                'Do something with the data object here.
                RaiseEvent DataReceived(client.Buffer, read, CType(client.TcpClient.Client.LocalEndPoint, IPEndPoint).Address.ToString())
                'Then start reading from the network again.
                networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, AddressOf ReadCallback, client)
            Catch ex As Exception
            End Try
        End Sub
 
#Region "Class Client"
        ''' <summary>
        ''' Internal class to join the TCP client and buffer together
        ''' for easy management in the server
        ''' </summary>
        Class Client
            ''' <summary>
            ''' Constructor for a new Client
            ''' </summary>
            ''' <param name="tcpClient">The TCP client</param>
            ''' <param name="buffer">The byte array buffer</param>
            Public Sub New(ByVal tcpClient As TcpClient, ByVal buffer() As Byte)
                If tcpClient Is Nothing Then
                    Throw New ArgumentNullException("tcpClient")
                End If
                If buffer Is Nothing Then
                    Throw New ArgumentNullException("buffer")
                End If
                Me.TcpClient = tcpClient
                Me.Buffer = buffer
            End Sub
 
            ''' <summary>
            ''' Gets the TCP Client
            ''' </summary>
            Public Property TcpClient As TcpClient
 
            ''' <summary>
            ''' Gets the Buffer.
            ''' </summary>
 
            Public Property Buffer As Byte()
 
            ''' <summary>
            ''' Gets the network stream
            ''' </summary>
 
            Public ReadOnly Property NetworkStream As NetworkStream
                Get
                    Return TcpClient.GetStream()
                End Get
            End Property
        End Class
#End Region
 
    End Class
 
    ''' <summary>
    ''' An Asynchronous TCP Client
    ''' </summary>
    Public Class AsyncTcpClient
 
#Region "Properties"
        Private Addresses As IPAddress()
        Private Port As Integer
        Private AddressesSet As WaitHandle
        Private TcpClient As TcpClient
        Private FailedConnectionCount As Integer
        Public Property Encoding As Encoding
        Public Event DataReceived(ByRef Data() As Byte, ByRef DataLength As Integer)
#End Region
 
#Region "Constructeurs"
        ''' <summary>
        ''' Construct a new client from a known IP Address
        ''' </summary>
        ''' <param name="address">The IP Address of the server</param>
        ''' <param name="port">The port of the server</param>
        Public Sub New(ByVal address As IPAddress, ByVal port As Integer)
            Me.New(New IPAddress() {address}, port)
        End Sub
 
        ''' <summary>
        ''' Construct a new client where multiple IP Addresses for
        ''' the same client are known.
        ''' </summary>
        ''' <param name="addresses">The array of known IP Addresses</param>
        ''' <param name="port">The port of the server</param>
        Public Sub New(ByVal addresses As IPAddress(), ByVal port As Integer)
            Me.New(port)
            Me.Addresses = addresses
        End Sub
 
        ''' <summary>
        ''' Construct a new client where the address or host name of
        ''' the server is known.
        ''' </summary>
        ''' <param name="hostNameOrAddress">The host name or address of the server</param>
        ''' <param name="port">The port of the server</param>
        Public Sub New(ByVal hostNameOrAddress As String, ByVal port As Integer)
            Me.New(port)
            AddressesSet = New AutoResetEvent(False)
            Dns.BeginGetHostAddresses(hostNameOrAddress, AddressOf GetHostAddressesCallback, Nothing)
        End Sub
 
        ''' <summary>
        ''' Private constuctor called by other constuctors
        ''' for common operations.
        ''' </summary>
        ''' <param name="port"></param>
        Private Sub New(ByVal port As Integer)
            If port < 0 Then
                Throw New ArgumentException()
            End If
            Me.Port = port
            Me.TcpClient = New TcpClient()
            Me.Encoding = Encoding.Default
        End Sub
#End Region
 
#Region "Connect"
        ''' <summary>
        ''' Attempts to connect to one of the specified IP Addresses
        ''' </summary>
        Public Sub Connect()
            If AddressesSet IsNot Nothing Then
                'Wait for the addresses value to be set
                AddressesSet.WaitOne()
            End If
            'Set the failed connection count to 0
            Interlocked.Exchange(FailedConnectionCount, 0)
            'Start the async connect operation
            TcpClient.BeginConnect(Addresses, Port, AddressOf ConnectCallback, Nothing)
        End Sub
 
        ''' <summary>
        ''' Callback for Connect operation
        ''' </summary>
        ''' <param name="result">The AsyncResult object</param>
        Private Sub ConnectCallback(ByVal result As IAsyncResult)
            Try
                TcpClient.EndConnect(result)
            Catch ex As Exception
                'Increment the failed connection count in a thread safe way
                Interlocked.Increment(FailedConnectionCount)
                If (FailedConnectionCount >= Addresses.Length) Then
                    'We have failed to connect to all the IP Addresses connection has failed overall.
                    Exit Sub
                End If
            End Try
            'We are connected successfully.
            Dim networkStream As NetworkStream = TcpClient.GetStream()
            Dim buffer(TcpClient.ReceiveBufferSize) As Byte
            'Now we are connected start asyn read operation.
            networkStream.BeginRead(buffer, 0, buffer.Length, AddressOf ReadCallback, buffer)
        End Sub
#End Region
 
#Region "Write"
        ''' <summary>
        ''' Writes a string to the network using the defualt encoding.
        ''' </summary>
        ''' <param name="data">The string to write</param>
        ''' <returns>A WaitHandle that can be used to detect
        ''' when the write operation has completed.</returns>
        Public Sub Write(ByVal data As String)
            Dim bytes() As Byte = Encoding.GetBytes(data)
            Write(bytes)
        End Sub
 
        ''' <summary>
        ''' Writes an array of bytes to the network.
        ''' </summary>
        ''' <param name="bytes">The array to write</param>
        ''' <returns>A WaitHandle that can be used to detect
        ''' when the write operation has completed.</returns>
        Public Sub Write(ByVal bytes() As Byte)
            Dim networkStream As NetworkStream = TcpClient.GetStream
            'Start async write operation
            networkStream.BeginWrite(bytes, 0, bytes.Length, AddressOf WriteCallback, Nothing)
        End Sub
 
        ''' <summary>
        ''' Callback for Write operation
        ''' </summary>
        ''' <param name="result">The AsyncResult object</param>
        Private Sub WriteCallback(ByVal result As IAsyncResult)
            Dim networkStream As NetworkStream = TcpClient.GetStream
            networkStream.EndWrite(result)
        End Sub
#End Region
 
#Region "Read"
        ''' <summary>
        ''' Callback for Read operation
        ''' </summary>
        ''' <param name="result">The AsyncResult object</param>
        Private Sub ReadCallback(ByVal result As IAsyncResult)
            Dim read As Integer
            Dim networkStream As NetworkStream
            Try
                networkStream = TcpClient.GetStream()
                read = networkStream.EndRead(result)
            Catch ex As Exception
                'An error has occured when reading
                Exit Sub
            End Try
 
            If read = 0 Then
                Exit Sub
            End If
 
            Dim buffer() As Byte = CType(result.AsyncState, Byte())
            Dim data As String = Me.Encoding.GetString(buffer, 0, read)
            'Do something with the data object here.
            RaiseEvent DataReceived(buffer, read)
            'Then start reading from the network again.
            networkStream.BeginRead(buffer, 0, buffer.Length, AddressOf ReadCallback, buffer)
        End Sub
 
#End Region
 
#Region "Diverses fonctions"
        ''' <summary>
        ''' Callback for Get Host Addresses operation
        ''' </summary>
        ''' <param name="result">The AsyncResult object</param>
        Private Sub GetHostAddressesCallback(ByVal result As IAsyncResult)
            Addresses = Dns.EndGetHostAddresses(result)
            'Signal the addresses are now set
            CType(AddressesSet, AutoResetEvent).Set()
        End Sub
#End Region
    End Class
 
End Module