Cette petite solution en VB 2005 sans prétention montre comment utiliser
un tcplistener selon deux méthodes.
Donc j'ai crée deux classes générant des évennements.
La classe Ecouteur utilise un Backgroundworker pour utiliser le tcplistener sans geler la classe elle même ou le programme utilisant la classe.
La classe TcpListener utilise un timer pour surveiller la propriètè pending du tcplistener, ce qui ne gelepas non plus la classe elle même ou le programme utilisant la classe.
J'ai essayer de bien documenter les deux classes afin de bien comprendre comment fonctionne le TcpListener ainsi que le BackgroundWorker
En Exemple ci dessous la classe sans Backgroundworker
Source / Exemple :
Imports System.Net
Imports System.Net.Sockets
Imports System.ComponentModel
Imports System.io
Public Class Ecouteur
#Region "Déclarations locales"
Private m_tcpl As TcpListener
Private WithEvents m_thread As BackgroundWorker
Private m_Etat As String
Private Structure DtTcp 'Objet utiliser pour intercommunication entre thread et controle Ecouteur
Dim sIP As IPAddress
Dim sPort As Integer
Dim sData As String
End Structure
Private m_dttcp As DtTcp
#End Region
#Region "Déclarations Evénements"
Public Event ErreurEcouter(ByVal Msg As String)
Public Event Etat(ByVal Etat As String)
Public Event DonneeRecu(ByVal MessageRecu As String)
#End Region
Public Sub New(ByVal IP As IPAddress, ByVal Port As Integer)
m_dttcp.sIP = IP
m_dttcp.sPort = Port
m_dttcp.sData = ""
End Sub
Public Sub Ecouter()
Try
'Paramètrage du backgroundworker
m_thread = New BackgroundWorker
m_thread.WorkerReportsProgress = True
m_thread.WorkerSupportsCancellation = True
'Déclaration des procédure pour gérer les evenements du backgroundworker
AddHandler m_thread.DoWork, AddressOf m_thread_DoWork
AddHandler m_thread.ProgressChanged, AddressOf m_thread_ProgressChanged
'Si pas déjà en execution lance le backgoundworker
If Not m_thread.IsBusy Then m_thread.RunWorkerAsync(m_dttcp)
Catch ex As Exception
'Déclenche Evenement Erreur
RaiseEvent ErreurEcouter(ex.Message)
End Try
End Sub
Public Sub Arreter()
Try
'Demande l'arret par cancel du backgroundworker
m_thread.CancelAsync()
'Création d'un client local pour déclencher la boucle infinie du backgroundworker
Dim TmpTcp As System.Net.Sockets.TcpClient
Dim StrCli As System.Net.Sockets.NetworkStream
Dim StrW As System.IO.StreamWriter
TmpTcp = New System.Net.Sockets.TcpClient
TmpTcp.Connect(m_dttcp.sIP, m_dttcp.sPort)
StrCli = TmpTcp.GetStream()
StrW = New System.IO.StreamWriter(StrCli)
StrW.Write("truc pour declencher le AcceptTcpClient dans le thread")
StrW.Close()
StrCli.Close()
TmpTcp.Close()
'Déclenche Evenement Etat avec info déconnecté
RaiseEvent Etat("Déconnecté")
Catch ex As Exception
'Déclenche Evenement Erreur
RaiseEvent ErreurEcouter(ex.Message)
End Try
End Sub
#Region "Fonctions du thread"
Private Sub m_thread_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles m_thread.DoWork
'Recup Thread
Dim LocThread As BackgroundWorker = CType(sender, BackgroundWorker)
'Recup Data
Dim LocDtTcp As DtTcp = e.Argument
'Créer Composant
m_tcpl = New TcpListener(LocDtTcp.sIP, LocDtTcp.sPort)
Try
Dim TcpCli As TcpClient
Dim m_str As NetworkStream
Dim m_read As StreamReader
Dim msg As String
While Not LocThread.CancellationPending 'Controle si arrêt demander
m_tcpl.Start() 'Mise en attente de connection
LocDtTcp.sData = "Attente connexion"
LocThread.ReportProgress(1, LocDtTcp) 'Mise à jour Etat hors du thread
'-------------------------------------------------------------------
'Boucle de controle de demande connections entrantes ou d'annulation
'Cette boucle a été supprimé et la procédure arreter modifiee pour déclencher le acceptcpclient
'Car cette boucle utilisait des ressources processeurs non négligeable (freeze du thread)
' While True
'If m_tcpl.Pending() Then Exit While
'If LocThread.CancellationPending Then
' m_tcpl.Stop()
' Exit While
' End If
'End While
'-------------------------------------------------------------------
TcpCli = m_tcpl.AcceptTcpClient() 'Créer un tcpclient pour récuperer les données
LocDtTcp.sData = "Connecté"
LocThread.ReportProgress(2, LocDtTcp) 'Mise à jour Etat hors du thread
m_str = TcpCli.GetStream 'Recup des données envoyées
m_read = New StreamReader(m_str) 'Lecteur du flux
msg = m_read.ReadToEnd 'Recup des données envoyées
m_read.Close()
m_str.Close()
LocDtTcp.sData = msg
LocThread.ReportProgress(3, LocDtTcp) 'Transfert du message hors du thread
m_tcpl.Stop()
End While
e.Cancel = True
Catch ex As Exception
m_tcpl.Stop()
LocDtTcp.sData = "Erreur : " + ex.Message
LocThread.ReportProgress(1, LocDtTcp)
End Try
End Sub
Private Sub m_thread_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles m_thread.ProgressChanged
Dim RepDtTcp As DtTcp = e.UserState
If e.ProgressPercentage = 1 Then
RaiseEvent Etat("Attente connection")
ElseIf e.ProgressPercentage = 2 Then
RaiseEvent Etat("Connecté")
ElseIf e.ProgressPercentage = 3 Then
RaiseEvent DonneeRecu(RepDtTcp.sData)
End If
End Sub
#End Region
End Class
Conclusion :
A vous d'exploiter cet exemple au mieux.
Je ne gère que de string en données envoyée / reçue, le but de l'exemple n'étant pas d'échanger tout type de données, mais de pouvoir établir une connection qui ne freeze pas l'application.)
Cordialement.
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.