Utilisation de socket [Résolu]

Messages postés
37
Date d'inscription
jeudi 4 février 2016
Dernière intervention
1 décembre 2018
-
Bonjour,
Voici mon problème, sa fais 3 jours intense que je cherche a réglé mon problème et j'ai tenté plusieurs chose et surement pas toujours bien exploité.

Je suis en construction d'un chat. Le serveur est un Form et non une console affin d'interagir plus facilement en t'en qu'administrateur et chaque client est une Form aussi. Pour le moment tout fonctionne sauf lorsque je clique sur le bouton ( Fermer le serveur ). Bref, le serveur crée un Thread sur le Serveur qui est en attente d'un client avec Accept() et bien évidement ce bloc et attend un cleint. S'il y a un client, il passe en construction du client avec un autre thread. C'est a dire le client envoie sont pseudo. Le serveur vérifie si le pseudo est déjà utilisé et le seveur retourne un message si le Pseudo est accepté ou refusé. S'il est accepté, un dernier thread pour chaque socket est lancé qui tourne en boucle. Si le Pseudo est refusé, le serveur retourne qu'il refuse le pseudo et alors les socket son fermer des 2 coté.

Jusque là, tout fonctionne nickel.

Puis viens le moment ou je clique sur fermer le serveur pour éventuellement le rouvrir possiblement plus tard sans fermer la Form, Form qui sera fort probablement implanter dans un autre programme plus tard.

Pour fermer le thread qui est présentement en attend d'un client, je dois utiliser MonSocketServeur.Close(). La le thread s'arrête. Sans ça, un client qui tente de ce connecter va ce voir la connexion autorisé et tombe en attente de recevoir le retour du serveur (Le thread traitement de la connexion) qui lui est maintenant désactivé, donc le client bloc. Mais lorsque par la suite, après avoir fait MonSocketServeur.Close() et que je clique sur le bouton (Connexion), j'ai une erreur qu'il peu pas travailler sur un objet supprimer. Cela fais présentement 1 grosse semaine que je travail a comprendre ce genre de programmation, c'est complètement nouveau pour moi.

Voici mon codage (J'ai suivi le cours sur le site (OpenClassroom) et j'ai reconstruit le code étape par étape pour tenté de le comprendre et suivre chaque action:

P.S. J'ai tenté Accept() avec Select() pour un timeout mais j'ai trouvé que du code C# et je ne suis pas capable de le traduire.

P.S. J'ai tenté aussi de créé une class spécifique au lancement du client que je pourais faire Thread.Abort() mais j'ai pas réussis a bien l'implanter et c'a fonctionnais pas. Sinon Si je fais MonThread.Abort() Qui est le Thread du Accept() sa bloque le programme complet.

Imports System.Net.Sockets
Imports System.Net
Imports System.Threading

Public Class Serveur
    Dim port As String = "8080"
    Dim ThreadServeur As Thread
    Dim MonSocketServeur As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    Dim MonEP As IPEndPoint = New IPEndPoint(IPAddress.Any, port)
    Shared Statut As Boolean
    Shared ListePseudo As New List(Of String)
    Shared ListeClients As List(Of Client) 'Liste destinée à contenir les clients connectés
    Delegate Sub dEcritServeurConsole(ByVal Message As String)
    Delegate Sub dUserListeMod(ByVal Pseudo As String, ByVal Ajout As Boolean)
    Delegate Sub dMessageConsole(ByVal Message As String)
    Delegate Sub dFonctionEnvoiTous(ByVal Message As String)
    Delegate Sub dStatutServeur(ByVal Statut As Boolean)
    Delegate Sub dFermerSocket()



    Private Sub Serveur_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        LBLStatut.BackColor = Color.LightYellow
        Dim ips() As IPAddress = Dns.GetHostAddresses(Dns.GetHostName)
        For Each ipa As IPAddress In ips
            If ipa.AddressFamily = Sockets.AddressFamily.InterNetwork Then
                EcritServeurConsole(DateTime.Now.ToString("dd-MM-yyyy") & "   " & TimeString & "   |   ADRESSE IP DU SERVEUR : " & ipa.ToString)
            End If
        Next

    End Sub

    Private Sub Serveur_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
        Statut = False
        For Each Cli In ListeClients
            Cli.FermerSocket()
        Next
        MonSocketServeur.Close()
        StatutServeur(Statut)
        EcritServeurConsole(DateTime.Now.ToString("dd-MM-yyyy") & "   " & TimeString & "   |   Fermeture du serveur ...")
        ListeClients.Clear()
        ListePseudo.Clear()
    End Sub

    ' ACTIONs DES OBJETS DE LA FORM

    Private Sub BTServStart_Click(sender As Object, e As EventArgs) Handles BTServStart.Click
        MonSocketServeur.Bind(MonEP) 'Lie le socket à cette IP
        ThreadServeur = New Thread(AddressOf Serveur)
        ThreadServeur.Start()
    End Sub

    Private Sub BTServStop_Click(sender As Object, e As EventArgs) Handles BTServStop.Click
        Statut = False
        For Each Cli In ListeClients
            Cli.FermerSocket()
        Next
        MonSocketServeur.Close()
        StatutServeur(Statut)
        EcritServeurConsole(DateTime.Now.ToString("dd-MM-yyyy") & "   " & TimeString & "   |   Fermeture du serveur ...")
        ListeClients.Clear()
        ListePseudo.Clear()
    End Sub

    Private Sub Exclusion_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If LSTUSER.SelectedItem = Nothing Then

        Else
            For Each Cli In ListeClients
                Dim Raison As String = InputBox("Raison :")
                Cli.DeconnectClient(LSTUSER.SelectedItem.ToString, Raison)
            Next
        End If

    End Sub

    ' FIN DES ACTIONS DES OBJETS DE LA FORM



    ' SUB TRAITANT LES OBJETS DE LA FORM

    Sub EcritServeurConsole(Message As String)
        TXTServConsole.Text = Message & vbCrLf & "----------------------------------------------------------------------------------------------------------" & vbCrLf & TXTServConsole.Text
    End Sub

    Sub StatutServeur(Statut As Boolean)
        If Statut = True Then
            BTServStart.Enabled = False
            BTServStop.Enabled = True
            LBLStatut.Text = "Serveur ON"
            LBLStatut.BackColor = Color.LightGreen
        Else
            BTServStart.Enabled = True
            BTServStop.Enabled = False
            LBLStatut.Text = "Serveur OFF"
            LBLStatut.BackColor = Color.LightYellow
        End If
    End Sub

    Sub MessageConsole(Message As String)

        Dim Origine As String
        Dim Nouveau As String
        Origine = TXTMessage.Text
        Nouveau = "----------------------------------------------------------------------------------------------------------" & Environment.NewLine & Origine
        TXTMessage.Text = Nouveau

        Origine = TXTMessage.Text
        Nouveau = Message & Environment.NewLine & Origine
        TXTMessage.Text = Nouveau
    End Sub

    Sub UserListeMod(ByVal Pseudo As String, ByVal Ajout As Boolean)
        If Ajout = True Then
            LSTUSER.Items.Add(Pseudo)
        Else
            LSTUSER.Items.Remove(Pseudo)
        End If
    End Sub



    ' FIN DES SUB TRAITANT LES OBJETS DE LA FORM



    ' SUB TRAITANT LE SERVEUR

    Sub Serveur()

        ListeClients = New List(Of Client) 'Initialise la liste
        MonSocketServeur.Listen(1) 'Se met en mode écoute
        Statut = True
        Me.Invoke(New dStatutServeur(AddressOf StatutServeur), Statut)
        Me.Invoke(New dEcritServeurConsole(AddressOf EcritServeurConsole), DateTime.Now.ToString("dd-MM-yyyy") & "   " & TimeString & "   |   SERVEUR LANCÉ !")
        While Statut = True 'Boucle à l'infini
            'Se met en attente de connexion et appelle TraitementConnexion() lors d'une connexion.
            Try
                Dim SocketEnvoi As Socket = MonSocketServeur.Accept() 'Bloquant tant que pas de connexion
                TraitementConnexion(SocketEnvoi)
            Catch ex As Exception

            End Try
        End While

    End Sub

    Sub TraitementConnexion(ByVal SocketEnvoi As Socket)
        Dim NouveauClient As New Client(SocketEnvoi) 'Crée une instance de « client »
        ListeClients.Add(NouveauClient) 'Ajoute le client à la liste

        'Crée un thread pour traiter ce client et le démarre
        Dim ThreadClient As New Thread(AddressOf NouveauClient.TraitementClient)
        ThreadClient.Start(Me)
    End Sub
    



    ' FIN DES SUB TRAITANT LE SERVEUR


    Private Class Client
        Private SocketClient As Socket 'Le socket du client
        Private Pseudo As String 'Le pseudo du client
        Private TraitementFonctionComplete As Boolean 'Le pseudo du client
        Public FrmSource



        'Constructeur
        Sub New(ByVal Sock As Socket)
            SocketClient = Sock
        End Sub
        Protected Overrides Sub Finalize()

        End Sub
        Sub FermerSocket()
            SocketClient.Close()
        End Sub

        Sub DeconnectClient(ByVal Nom As String, ByVal Raison As String)
            If Nom = Pseudo Then
                Dim Envoi As Integer = SocketClient.Send(System.Text.Encoding.UTF8.GetBytes("20//" & Raison))
                SocketClient.Close() 'Ferme son socket
            End If
        End Sub

        Sub TraitementClient(ByVal Source)
            TraitementFonctionComplete = True
            Dim Bytes(500) As Byte 'Tableau de 255 : on ne reçoit que 255 caractères au maximum
            Dim Recu As Integer
            FrmSource = Source
            'Le client vient de se connecter
            'Réception du premier message contenant le pseudo
            Try
                Recu = SocketClient.Receive(Bytes) 'Reçoit les premières données : le pseudo
            Catch ex As Exception
                FrmSource.Invoke(New dEcritServeurConsole(AddressOf FrmSource.EcritServeurConsole), DateTime.Now.ToString("dd-MM-yyyy") & "   " & TimeString & "   |   ERREUR : Le client ne c'est pas initialisé !")
                Return
            End Try

            Pseudo = System.Text.Encoding.UTF8.GetString(Bytes)
            Pseudo = Pseudo.Substring(0, Recu) 'Retire les caractères inutiles

            If Not ListePseudo.Contains(Pseudo) Then
                ListePseudo.Add(Pseudo)
                EnvoiMessageTous("10//PSEUDOACTUALISE")
                FrmSource.Invoke(New dEcritServeurConsole(AddressOf FrmSource.EcritServeurConsole), DateTime.Now.ToString("dd-MM-yyyy") & "   " & TimeString & "   |   " & Pseudo & " c'est connecté !")
                FrmSource.Invoke(New dUserListeMod(AddressOf FrmSource.UserListeMod), Pseudo, True)
                'Source.Invoke(New dFonctionEnvoiTous(AddressOf Source.FonctionEnvoiTous), "01//PSEUDOACTUALISE")
            Else
                SocketClient.Send(System.Text.Encoding.ASCII.GetBytes("REFUS"))
                SocketClient.Close()
                ListeClients.Remove(Me)
                FrmSource.Invoke(New dEcritServeurConsole(AddressOf FrmSource.EcritServeurConsole), DateTime.Now.ToString("dd-MM-yyyy") & "   " & TimeString & "   |   Une connection a été refusé !")
                Exit Sub
            End If

            While (SocketClient.Connected)
                If TraitementFonctionComplete = True Then
                    Try
                        Recu = SocketClient.Receive(Bytes)
                        Message = System.Text.Encoding.UTF8.GetString(Bytes)
                        Message = Message.Substring(0, Recu) 'Retire les caractères inutiles
                        TraitementFonctionComplete = False
                        MessageGEN = Message
                        TraitementMessage(Message)


                    Catch ex As Exception 'Le client est déconnecté
                        ListeClients.Remove(Me) 'Le supprime de la liste des clients connectés
                        SocketClient.Close() 'Ferme son socket
                        ListePseudo.Remove(Pseudo)
                        FrmSource.Invoke(New dUserListeMod(AddressOf FrmSource.UserListeMod), Pseudo, False)
                        EnvoiMessageTous("10//PSEUDOACTUALISE")
                        FrmSource.Invoke(New dEcritServeurConsole(AddressOf FrmSource.EcritServeurConsole), DateTime.Now.ToString("dd-MM-yyyy") & "   " & TimeString & "   |   " & Pseudo & " c'est déconnecté !")
                        Return 'Fin de la fonction
                    End Try
                End If
            End While

        End Sub
        Sub TraitementMessage(ByVal MessageSource As String)
            Dim Type As String
            Type = MessageSource.Substring(0, 2)
            Message = MessageSource.Substring(4, MessageSource.Length - 4)

            If Type = "00" Then
                EnvoiMessageTous("00//" & Pseudo & " : " & Message)
                FrmSource.Invoke(New dMessageConsole(AddressOf FrmSource.MessageConsole), Pseudo & " : " & Message)
            End If

            If Type = "10" Then
                If Message = "PSEUDOLISTE" Then
                    For Ligne = 0 To ListePseudo.Count - 1
                        Dim TraitementFonction As Boolean
                        TraitementFonction = False
                        SocketClient.Send(System.Text.Encoding.ASCII.GetBytes(ListePseudo(Ligne)))
                        Do While Not TraitementFonction = True
                            Try
                                Dim Bytes(255) As Byte 'Tableau de 255 : on ne reçoit que 255 caractères au maximum
                                Dim Recu As Integer
                                Recu = SocketClient.Receive(Bytes)
                                Message = System.Text.Encoding.UTF8.GetString(Bytes)
                                Message = Message.Substring(0, Recu) 'Retire les caractères inutiles
                                If Message = "NEXT" Then
                                    TraitementFonction = True
                                ElseIf Message = ("ERREUR") Then
                                    TraitementFonctionComplete = True
                                    Exit Sub
                                End If
                            Catch ExPseudo As Exception

                            End Try
                        Loop
                    Next
                    SocketClient.Send(System.Text.Encoding.ASCII.GetBytes("FINLISTE"))
                End If
                If Message = "HEURE" Then
                    SocketClient.Send(System.Text.Encoding.ASCII.GetBytes("00//" & Now.ToLongTimeString)) 'Envoie l'heure au client
                End If
            End If
            TraitementFonctionComplete = True
        End Sub
        Sub EnvoiMessage(ByVal Message As String)
            Dim Mess As Byte() = System.Text.Encoding.UTF8.GetBytes(Message)
            Dim Envoi As Integer = SocketClient.Send(Mess)
        End Sub
        Sub EnvoiMessageTous(ByVal Message As String)
            If Statut = True Then
                For Each Cli In ListeClients
                    Cli.EnvoiMessage(Message)
                Next
            End If
        End Sub
    End Class


End Class


EDIT : Ajout du LANGAGE dans les balises de code (la coloration syntaxique).
Explications disponibles ici : ICI

Merci d'y penser dans tes prochains messages.
Afficher la suite 

Votre réponse

2 réponses

Messages postés
12415
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
18 décembre 2018
0
Merci
Bonsoir

Tout d’abord, merci a NHenry d’avoir rendu ton code lisible.
Voir l'encart qu’il a ajouté en bas de ton message et surtout le lien vers « comment le faire toi même »
Parce que vois tu déjà, que 300 lignes écrites par un autre c’est pas simple à suivre, mais si en plus c’est en mode « node pad » personne ne va essayer et ta question restera sans réponse.

P.S. J'ai tenté Accept() avec Select() pour un timeout mais j'ai trouvé que du code C# et je ne suis pas capable de le traduire.
C’est pourtant très simple,
https://www.qwant.com/?q=C%23+to+vb&t=web

j'ai une erreur qu'il peu pas travailler sur un objet supprimer.
A quelle ligne et quelle est l’erreur exacte?

MaitreTeTe
Messages postés
37
Date d'inscription
jeudi 4 février 2016
Dernière intervention
1 décembre 2018
-
L'erreur ce créé la deuxième fois que je clique sur le bouton (Connexion) du serveur. Sois après avoir cliquer sur (Déconnexion) du serveur en utilisant MonSocketServeur.Close() (Qui celons ce que j'ai lu ferme et détruit le socket)

Private Sub BTServStart_Click(sender As Object, e As EventArgs) Handles BTServStart.Click
        MonSocketServeur.Bind(MonEP) 'Lie le socket à cette IP
        ThreadServeur = New Thread(AddressOf Serveur)
        ThreadServeur.Start()
    End Sub


J'ai tenté de déplacé cette ligne de commande mais sa change rien
Dim MonSocketServeur As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
Whismeril
Messages postés
12415
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
18 décembre 2018
-
Quelle ligne exactement et quelle erreur exactement?
MaitreTeTe
Messages postés
37
Date d'inscription
jeudi 4 février 2016
Dernière intervention
1 décembre 2018
-
J'AI TROUVÉ !!!!!!

Alors Voici ma solution:
Au lieu d'écrire ceci dans les variable de ma class :
Dim MonSocketServeur As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)


J'ai écris ceci :
Dim MonSocketServeur As Socket


Et si j'écrivais ceci sur mon bouton (Connexion du serveur)
Private Sub BTServStart_Click(sender As Object, e As EventArgs) Handles BTServStart.Click
        Dim MonSocketServeur As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
               MonSocketServeur.Bind(MonEP) 'Lie le socket à cette IP
        ThreadServeur = New Thread(AddressOf Serveur)
        ThreadServeur.Start()
    End Sub

Et bien dans les autres Sub automatiquement MonSocketServeur devenais Nothing Meme si dans ma class de ma form j'avais le code Dim MonSocketServeur As Socket

Alors j'ai tenté cette methode et ça passe !!!!!
Private Sub BTServStart_Click(sender As Object, e As EventArgs) Handles BTServStart.Click
        Dim MonSocketServeurLance As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        MonSocketServeur = MonSocketServeurLance
        MonSocketServeur.Bind(MonEP) 'Lie le socket à cette IP
        ThreadServeur = New Thread(AddressOf Serveur)
        ThreadServeur.Start()
    End Sub


Résultat, tout Fonctionne !!!
Merci beaucoup pour votre aide. Après trois jour de recherche infructueuse, Soulagement !
Whismeril
Messages postés
12415
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
18 décembre 2018
-
Je vais tempérer ton enthousiasme.
C’est sympa de me remercier, mais je n’ai pas encore fait grand chose.
Maintenant, j’ai un peu plus d’éléments, je vais pouvoir éclairer un point où deux.

D’abord, ajouter un bout de code par-ci, en enlever un par-là peut parfois résoudre ton problème. Mais le comprendre est plus efficace.

Tu avais un problème de portée de variable.
Une variable existe à partir du moment où elle a un nom, un type et une valeur.
Mais elle est aussi cloisonnée à une « zone géographique ».
Elle débute à un endroit, et finit quand elle croise un
End TrucMuche

C’est ce qu’on appelle la portée.

Class UnTruc
    Dim maVariable as new QuelqueChose 'maVariable existe jusqu’à End Class


Mais, y’a un mais. Il peut exister dans une « sous zone géographique » une variable du même nom, et ce seront 2 variables différentes.

Class UnTruc
    Dim maVariable as QuelqueChose 'maVariable vaut Nothing, y’a pas de New

   Sub Bidule()
           Dim maVariable as new QuelqueChose 'maVariable existe jusqu’à End Sub et n’est pas la même que celle de la classe
   End Sub
   
   Sub Machin()
         maVariable.Chose()  'maVariable c’est celle de la classe, elle vaut Nothing => erreur
   End Sub

Commenter la réponse de Whismeril
Messages postés
37
Date d'inscription
jeudi 4 février 2016
Dernière intervention
1 décembre 2018
0
Merci
Oui, merci beaucoup a NHenry, je croyais avoir fais de la bonne façon, mais à voir sa modification je me rend bien compte que non hihihi!

Merci beaucoup a toi aussi Whismeril. je vais aller regarder ça. Je vous tiens au courant.
Commenter la réponse de MaitreTeTe

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.