Les sockets aiment les msgbox

[Résolu]
Signaler
Messages postés
19
Date d'inscription
dimanche 14 août 2005
Statut
Membre
Dernière intervention
20 septembre 2010
-
Messages postés
840
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
-
Bonsoir, je suis actuellement face à une énigme dérangeante.

En effet, j'ai programmé un serveur simpliste en utilisant system.net.sockets.
Or, il s'est vite avéré que mon serveur plantait dès que je tentais de le mettre en écoute.
Pour tenter de réparer le problème, j'ai coutume de mettre des msgbox un peu partout ( sa permet de cibler un peu plus le problème).
Et là, c'est le drame!
Lorsque mon programme est blindé de msgbox, il fonctionne au poil, alors quil se remet a planter dès que je les enlève. Je me suis dit que certaines commandes du sockets necessitaient un peu de temps à s'executer et que les msgbox lui offrait ce temps, idée stupide que j'ai abandonné que j'ai remarqué que le programme plantait toujours autant lorsque je remplaçais les fameuses msgbox par des sleep().

Je commence à desesperer, et toute réponse est plus que bienvenue, merci d'avance.

Voici le code:

Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports Microsoft.VisualBasic

Public Class Form1
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim server As TcpListener
server = Nothing
MsgBox("plop")
Dim port As Int32
port = Val(TextBox1.Text.ToString)
MsgBox("plop")
Dim localAddr As IPAddress = IPAddress.Parse("127.0.0.1")
server = New TcpListener(localAddr, port)
MsgBox("plop")
server.Start()
Button1.Enabled = False
MsgBox("plop")
Dim bytes(1024) As Byte
Dim data As String = Nothing
MsgBox("plop")
Dim contenu As String = "rien"
Label1.Text = "Ecoute lancée, en attente... "
MsgBox("plop")
Label1.ForeColor = Color.Blue
MsgBox("plop")

Dim client As TcpClient = server.AcceptTcpClient()
Label1.Text = "Connecté"
Label1.ForeColor = Color.Green
Console.Beep(40, 100)
Console.Beep(60, 100)
Dim stream As NetworkStream = client.GetStream()
Dim i As Int32
While contenu <> "/quit"
Try
data = Nothing
i = stream.Read(bytes, 0, bytes.Length)
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
contenu = data.ToString
If contenu <> "/quit" Then
MsgBox("message reçu: " & data.ToString)
End If
Catch
MsgBox("Connexion avec l'hôte perdue !", MsgBoxStyle.Critical)
contenu = "/quit"
End Try
End While
server.Stop()
Me.Close()
End Sub
End Class

12 réponses

Messages postés
840
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
9
"Effectivement le programme ne repond plus, mais il n'a meme pas le
temps d'executer la ligne "label1.text=Ecoute lancée, en attente..."
car le label ne change pas de tête."
Si si, la ligne label1.text=Ecoute lancée, en attente...est forcément exécuté, seulement tu ne le vois pas
Vu que ton code qui suit cette ligne est bloquant, l'affichage ne se met pas à jour et donc on ne voit pas le texte de label1 changer
Une solution serait de faire un DoEvents après cette ligne, ce qui mettrait l'affichage à jour avant d'entrer dans une fonction bloquante, mais il faut avouer que ma technique du message précédent est bien meilleur (pas de "Ne répond plus", possibilité d'annuler l'écoute, début pour pouvoir accepter plusieurs clients, etc...)

Et d'ailleurs, c'est pour ça que ton code semble mieux fonctionner lorsque tu utilise des MessageBox, car l'affichage de ton formulaire principal est rafraichit lorsque on affiche une MessageBox
Messages postés
19
Date d'inscription
dimanche 14 août 2005
Statut
Membre
Dernière intervention
20 septembre 2010

Oula, j'espere que vous voyez pas mon post avec le code tout regroupé comme moi...

Si c'est le cas, je veux bien une explication pour lui remettre une tête correcte, merci
Messages postés
3275
Date d'inscription
jeudi 3 avril 2008
Statut
Membre
Dernière intervention
14 septembre 2014
4
ce code est illisible voudrais tu s'il te plait le présenter proprement

Bonjour chez vous !
Messages postés
19
Date d'inscription
dimanche 14 août 2005
Statut
Membre
Dernière intervention
20 septembre 2010

Avec plaisir, mais quand je poste, tous les retour chariots et les tabulation que je met a mon code se barrent. pour faire cet infâme paté. quelque chose de particulier a faire pour ne pas que cela soit ignoré?
Messages postés
3275
Date d'inscription
jeudi 3 avril 2008
Statut
Membre
Dernière intervention
14 septembre 2014
4
moi je copy paste directement depuis vb2005 dans la freetextbox et ça fonctionne très bien mais il y a aussi
 http://tools.codes-sources.com/colorizeCode.aspx

Bonjour chez vous !
Messages postés
840
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
9
"moi je copy paste directement depuis vb2005 dans la freetextbox et ça fonctionne très bien mais il y a aussi"

Très bien tu dis? Avec ces suppressions d'espaces et ces retours à la ligne non voulu, c'est franchement désagréable de lire un code, en tout cas moi j'ai horreur de ça

Moi je conseil un copier-coller en passant par le bloc-note, ça permet de supprimer toutes les mises en forme.

Mais j'ajoute quand même que lorsque je fais un copier-coller depuis l'IDE de VB, ça ne me donne pas un gros bloc comme ceci, toutefois tu n'es pas le seul à qui ça arrive.
Messages postés
3275
Date d'inscription
jeudi 3 avril 2008
Statut
Membre
Dernière intervention
14 septembre 2014
4
pour moi ce sont des détails Kevin,par rapport à un gros bloc comme ci dessus

Bonjour chez vous !
Messages postés
840
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
9
"pour moi ce sont des détails Kevin,par rapport à un gros bloc comme ci dessus"

Ah mais oui, ceci ne se discute pas Gillardg, on est bien d'accord

Bon, sympa comme je suis, je refais la mise en forme (en simplifiant)

Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports Microsoft.VisualBasic

Public Class Form1

  Private Sub Button1_Click(...) Handles Button1.Click
    Button1.Enabled = False

    Dim server As TcpListener
    Dim port As Int32 = Val(TextBox1.Text.ToString)
    Dim localAddr As IPAddress = IPAddress.Parse("127.0.0.1")
    server = New TcpListener(localAddr, port)
    server.Start()

    Dim bytes(1024) As Byte
    Dim data As String = Nothing
    Dim contenu As String = "rien"
    Label1.Text = "Ecoute lancée, en attente... "
    Label1.ForeColor = Color.Blue
    Dim client As TcpClient = server.AcceptTcpClient()
    Label1.Text = "Connecté"
    Label1.ForeColor = Color.Green
    Dim stream As NetworkStream = client.GetStream()
    Dim i As Int32
    While contenu <> "/quit"
      Try
        i = stream.Read(bytes, 0, bytes.Length)
        data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
        contenu = data.ToString
        If contenu <> "/quit" Then
          MsgBox("message reçu: " & data.ToString)
        End If
      Catch
        MsgBox("Connexion avec l'hôte perdue !", MsgBoxStyle.Critical)
        contenu = "/quit"
      End Try
    End While
    server.Stop()
    Me.Close()
  End Sub
End Class

sniceper>
"Or, il s'est vite avéré que mon serveur plantait dès que je tentais de le mettre en écoute"
J'ai envie de poser la question suivante: que veux-tu dire par "planter" ?
Si tu veux dire par là que ton application ne répond plus, c'est absolument normal puisque server.AcceptTcpClient() et stream.Read() sont des fonctions bloquantes, même chose pour un Sleep. Pour résoudre ce problème, il faut soit utiliser les fonctions non-bloquantes (server.BeginAcceptTcpClient et stream.BeginRead) ou utiliser un 2ème thread pour la lecture.
Messages postés
19
Date d'inscription
dimanche 14 août 2005
Statut
Membre
Dernière intervention
20 septembre 2010

oui je suis d'accord, mais le problème ne vient pas de là.
Effectivement le programme ne repond plus, mais il n'a meme pas le temps d'executer la ligne "label1.text=Ecoute lancée, en attente..." car le label ne change pas de tête. A moins que "server = New TcpListener(localAddr, port)
server.Start()" ne soit bloquant aussi?

Et merci beaucoup pour la remise en page, c'est tres sympa.
Messages postés
840
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
9
Regarde ce code, tapé à la va-vite et pas testé, mais je crois qu'il devrait fonctionner:

Imports System.Net
Imports System.Net.Sockets

Public Class Form1

    Private WithEvents Worker As New System.ComponentModel.BackgroundWorker

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Lancer l'écouteur dans un thread en arrière-plan
        Worker.WorkerReportsProgress = True
        Worker.RunWorkerAsync(Val(TextBox1.Text.ToString))
    End Sub

  Private Sub Worker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles Worker.DoWork
        ' Ecouter les connexions entrantes
        Dim listener As New TcpListener(IPAddress.Parse("127.0.0.1"), e.Argument)
        listener.Start()

        ' Accepter un client
        Dim Client As TcpClient = listener.AcceptTcpClient()
        Dim Stream As NetworkStream = Client.GetStream
        Dim Buffer(Client.ReceiveBufferSize - 1) As Byte

        ' Lire les messages entrants
        Do
            Dim Len As Integer = Stream.Read(Buffer, 0, Buffer.Length)
            Dim Message As String = System.Text.Encoding.ASCII.GetString(Buffer, 0, Len)

            If Message <> "/quit" Then
                Worker.ReportProgress(0, Message)
            Else
                Exit Do
            End If
        Loop
    End Sub

    Private Sub Worker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles Worker.ProgressChanged
        ' Afficher un message reçu
        MsgBox(e.UserState)
    End Sub

End Class

Une limitation avec ce code, c'est que si un message fait plus de 'Client.ReceiveBufferSize'caractères (c'est à dire la taille du buffer de réception), les données seront coupés en plusieurs messages.
On peut aussi utiliser un BinaryReader pour lire les données reçue, ce qui simplifie la choses et élimine la limitation de l'autre technique, mais je crois que le fonctionnement n'est pas le même (à vérifier, codage du texte <> ASCII !):

    Private Sub Worker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles Worker.DoWork
        ' Ecouter les connexions entrantes

        Dim listener As New TcpListener(IPAddress.Parse("127.0.0.1"), e.Argument)

        listener.Start()

        ' Accepter un client

        Dim Client As TcpClient = listener.AcceptTcpClient()

        Dim Reader As New IO.BinaryReader(Client.GetStream)

        ' Lire les messages entrants

        Do

            Dim Message As String = Reader.ReadString

            If Message <> "/quit" Then

                Worker.ReportProgress(0, Message)

            Else

                Exit Do

            End If

        Loop

    End Sub
Messages postés
19
Date d'inscription
dimanche 14 août 2005
Statut
Membre
Dernière intervention
20 septembre 2010

okayyyy!!! fiew c'est bon je capte le principe.
Effectivement utiliser le listener en arriere plan et je vois a peu pres comment l'adapter pour la connexion multi-client.
Merci beaucoup de la précision et la clarté de tes explications.



(je me ferais jamais à la sympathie des gens sur ce forum ^^)


Bonne soirée.
Messages postés
840
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
9
Pas de quoi, et bonne continuation