Client socket

Messages postés
21
Date d'inscription
mardi 23 juin 2009
Statut
Membre
Dernière intervention
23 juin 2009
- - Dernière réponse : pintux
Messages postés
21
Date d'inscription
mardi 23 juin 2009
Statut
Membre
Dernière intervention
23 juin 2009
- 18 août 2008 à 22:00
Bonjour à tous,


J’essaye d’écrire un client –serveur en vb.net pour le
serveur tout va bien puisque lorsque je le questionne via un telnet, il m’envoie
bien l’information attendue. Par contre côté client c’est <st1:personname productid="la Cata" w:st="on">la Cata</st1:personname>,ça par en vrille, voici
un extrait de mon code



 





Public

Class Form1






 







   
Private socket AsNew Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp)






   
Private IPAdresse As
IPAddress = System.Net.IPAddress.Parse("192.168.0.2")






   
Private iPEndPoint As
IPEndPoint = New
System.Net.IPEndPoint(IPAdresse, 1960)






   
Private Message AsByte()






   
Private BufferDonnées As
System.Text.StringBuilder = New
System.Text.StringBuilder("")






   
Private threadClient AsNew Thread(AddressOf
TraitementClient)






 







 







   
Private
Sub
ButtonClient_Click(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles
ButtonClient.Click






        threadClient.Start()






   
End
Sub







 







   
Private
Sub
TraitementClient()






       
socket.Connect(iPEndPoint)






       
If (socket.Connected) Then






           
MsgBox("Client connecté",
MsgBoxStyle.Information, "Socket connecté")






       
End
If







       
Try







           
socket.Receive(Message)






           
For
Each val AsByteIn Message






               
Dim s AsString = Chr(val)






                BufferDonnées.Append(s)






           
Next







           
Dim résultat AsString = BufferDonnées.ToString






           
TextBoxClient.Text = résultat






       
Catch erreur As
SocketException






       
End
Try







       
threadClient.Abort()






       

ButtonClient.Text
= "OK"






   
End
Sub






End

Class







 






A chaque fois j’ai une alerte «L'exception
System.ArgumentNullException n'a pas été gérée





La valeur ne peut pas être null.





Nom du paramètre : buffer"






 






Cela laisse penser que le tableau de byte Message
soit null, pourtant en passant par telnet je récupère bien des données, ce qui
prouve que le serveur n’envoie pas un élément null.





J’ai déjà fait du client-serveur en Java, j’avoue
que c’est moins prise de tête.






 






Merci pour toutes aides apportées






 







 








Philippe
Afficher la suite 

10 réponses

Messages postés
843
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
5
0
Merci
Salut,

Même si ton client recoit des données, la variable Message doit quand même être valide, ce qui n'est pas le cas car tu là déclare en tableau vide. Tu dois donc déclarer la taille du tableau, un truc de ce genre serait l'idéal:
Private Message(Socket.ReceiveBufferSize)As Byte

Autre info, il y a d'autre classe dans le framework qui pourrait nettement te simplifier la vie. Je pense notamment à la classe TcpClient, qui permet des envois/réceptions asynchrones (donc inutile de déclarer un nouveau thread) ainsi que d'autre améliorations que je te laisse découvrir.
Si tu veux tout de même utiliser un autre thread, il y a le BackgroundWorker qui est très utile et nettement plus simple d'utilisation que de déclarer soit même un thread (pour le passage d'info entre les threads notamment)
Pour passer de ton buffer de bytes (Message) à du texte et vice versa, utilise un codeur/décodeur que tu trouvera dans le namespace System.Text. Ca te permettra de transformer la totalité de ton buffer en String, sans devoir utiliser ta très très lente boucle utilisant la fonction char.
Commenter la réponse de Kevin.Ory
Messages postés
21
Date d'inscription
mardi 23 juin 2009
Statut
Membre
Dernière intervention
23 juin 2009
0
Merci
Salut Kevin,
D'abord, merci pour ton intéret.J'ai essayé de déclarer Le tableau, comme tu me l'as sugéré.
Private Message(Socket.ReceiveBufferSize)As Byte
Mais cela génère une erreur dans Visual Studio
Erreur    1    Impossible de spécifier des modificateurs de tableau pour la variable et son type.
Je vais essayé d'utiliser la classe TspClient qui en effet à l'air sympa.

Cordialement

Philippe
Commenter la réponse de pintux
Messages postés
843
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
5
0
Merci
Heu.. ce n'est pas normal ça..
Et si tu utilise une constante plutôt que Socket.ReceiveBufferSize? (Je ne suis pas sur du nom de cette propriété)
Private Message(1024) As Byte
Commenter la réponse de Kevin.Ory
Messages postés
21
Date d'inscription
mardi 23 juin 2009
Statut
Membre
Dernière intervention
23 juin 2009
0
Merci
Salut Kevin,


J’ai tout repris à plat avec donc un Objet de
type TCPClient, voici mon code



 





Imports
System.Net





Imports
System.Net.Sockets





Imports
System.Text






 






Public

Class Form1






 







   
'Private socket As New Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp)







   
Private IPAdresse As
IPAddress = System.Net.IPAddress.Parse("192.168.0.2")






   
Private iPEndPoint As
IPEndPoint = New
System.Net.IPEndPoint(IPAdresse, 1960)






   
Private tcpClient As
System.Net.Sockets.TcpClient = New
System.Net.Sockets.TcpClient(iPEndPoint)






   
'Private callback As AsyncCallback







   
'Private longueur As Integer = Socket.ReceiveBufferSize







   
Private Message(tcpClient.Available) AsByte






   
'Private BufferDonnées As System.Text.StringBuilder = New
System.Text.StringBuilder("")







 







   
Private
Sub
ButtonClient_Click(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles
ButtonClient.Click






        tcpClient.Connect(iPEndPoint)






       
If (tcpClient.Connected) Then






            ButtonClient.Text
= "Connecté"






       
End
If







       
Dim LongueurDonnées AsInteger = tcpClient.ReceiveBufferSize






        tcpClient.Client.Receive(Message,
tcpClient.Available, SocketFlags.None)






       
Dim msg AsString =
System.Text.Encoding.Unicode.GetString(Message)






        TextBoxClient.Text
= msg






       
tcpClient.Close()






   

End

Sub






End

Class







 






Cela se passe bien du côté buffer. Néanmoins
lorsque je lance le client j’obtient le message suivant






 





Une erreur s'est produite lors de la création du formulaire.
Pour plus d'informations, consultez Exception.InnerException. L'erreur est :
Une seule utilisation de chaque adresse de socket (protocole/adresse
réseau/port) est habituellement autorisée



 




Il semble que le client ne puisse pas avoir le même
IPEndPoint que le serveur. Pourtant c’est la base du principe client –serveur.
En effet, le serveur est en écoute sur une machine identifiée par son IP et
cette écoute se fait sur un port X. Le client doit donc s’adresser à cette même
adresse IP afin d’atteindre la machine qui héberge le service et sur le port X
afin de solliciter ce service. Voici des années que je travaille en réseau et j’ai
toujours constaté ce principe de fonctionnement en client-serveur.Du reste
lorsque l’on développe en Java la conception se fait sur ces fondements.


En vb.net, Visual Studio m’insulte, si le serveur et le
client ont le même IPEndPoint. Et dans le cas contraire, rien ne fonctionne, ce
qui est logique.


Je ne vois pas d’autre solution que d’avoir un IPEndPoint
avec les mêmes valeurs pour le serveur et le client. A moins que Microsoft a
réinventé le client-serveur !!!



 Très Cordialement




Philippe
Commenter la réponse de pintux
Messages postés
843
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
5
0
Merci
Je dois dire que je ne sais plus comment on fait une réception multicast, mais pour faire une simple connexion client-serveur, le serveur écoute la connexion entrante avec un TcpListener.

Voici à quoi ça ressemble (un seul thread (interface bloquante) et un seul client) :

Private Sub frmServer_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
    ' Adresse et port à écouter
    Dim listener As New TcpListener(IPAddress.Parse("127.0.0.1"), 3456)
    ' Démarrer le Listener
    listener.Start()
    ' Attente d'une connexion entrante (bloquant)
    Dim client As TcpClient = listener.AcceptTcpClient()
    ' Obtenir le stream
    Dim s As NetworkStream = client.GetStream
    ' Buffer pour les données réçues
    Dim Buffer(client.ReceiveBufferSize) As Byte
    Try
        Do
            ' Lire les données (bloquant)
            Dim len As String = s.Read(Buffer, 0, client.ReceiveBufferSize)
            ' Conversion Bytes => String
            Dim message As String = System.Text.Encoding.Unicode.GetString(Buffer, 0, len)
            ' Afficher le message
            txtLog.AppendText(message & vbCrLf)
            ' Rafraichir l'affichage
            Application.DoEvents()
        Loop
    Catch ex As Exception
    End Try
End Sub

De cette façon, on obtient un TcpClient par client qui s'est connecté...
Commenter la réponse de Kevin.Ory
Messages postés
21
Date d'inscription
mardi 23 juin 2009
Statut
Membre
Dernière intervention
23 juin 2009
0
Merci
Salut Kevin,



 




D’abord merci pour ton aide. Côté serveur, j’ai procédé de
façon un peu différente, car j’ai utilisé un objet de type Socket dans un
thread, cela donne un code un peu moins clair, mais cela fonctionne aussi très
bien, j’ai testé avec plusieurs telnet lancés en parallèle, et tout est OK. C ‘est
lorsque je lance le client, que je me fais insulté, et uniquement si le serveur
est déjà lancé. Ce qui démontre bien une incidence entre le serveur et le client, du
reste le message d’erreur ne laisse aucun doute "Une seule utilisation de chaque adresse
de socket (protocole/adresse réseau/port) est habituellement autorisée". Ce qui bloque c’est bien qu’il existe 2 sockets ayant les mêmes paramètres (protocole/adresse
réseau/port), mais cela me parait indispensable pour que le client et le
serveur puisse échanger des infos, je ne vois pas comment il pourrait en être
autrement. Pour que 2 entités dialoguent, il est nécessaire de le faire sur une
même base. Il en est de même pour un client et un serveur, même protocole, même
port, et bien sûr le client doit se brancher sur l’adresse IP de la machine qui
héberge le service. Mais, ce mode de fonctionnement ne semble pas compatible
avec le framework .NET.


J’avoue qu’après plusieurs années de travail dans le monde
des réseaux, et après avoir développé des outils de supervision réseau (Java) ;
j e reste sans voie devant un tel message qui va à l’encontre du modèle client-serveur
.Je ne trouve donc pas de justification à ce message, qui néanmoins est
bloquant. Je souhaitais donc juste comprendre l’origine de celui-ci, si il
sagissait d’une limitation propre au framework .Net, d'un bug, ou à d'un nouveau modèle client-serveur ?



 




Très cordialement



 




Philippe
Commenter la réponse de pintux
Messages postés
843
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
5
0
Merci
Il est possible d'écouter les connexions entrantes avec un socket, c'est indiqué sur MSDN, et d'ailleur TcpListener utilise un socket pour jouer son rôle. Par contre, c'est impossible avec un TcpClient, qui n'a pas été créé pour ça et qui doit être utilisé de pair avec un TcpListener.
Tu essaie d'écouter les connexion entrante avec un TcpClient dans ton serveur?
Il faut soit utiliser un TcpListener, soit configurer un Socket de la bonne façon. Je crois qu'il y a un exemple complet sur MSDN d'un serveur asynchrone en utilisant des sockets.
La classe Socket est un wrapper de l'API socket de Windows, rien n'a été réinventé... seul les classe TcpClient et TcpListener sont nouvelles.
Commenter la réponse de Kevin.Ory
Messages postés
843
Date d'inscription
mercredi 22 octobre 2003
Statut
Membre
Dernière intervention
7 janvier 2009
5
0
Merci
Voici l'exemple pour un serveur asynchrone :http://msdn.microsoft.com/fr-fr/library/fx6588te(VS.80).aspx
Il y a aussi un exemple pour un serveur synchrone....
Commenter la réponse de Kevin.Ory
Messages postés
21
Date d'inscription
mardi 23 juin 2009
Statut
Membre
Dernière intervention
23 juin 2009
0
Merci
Salut Kevin,


Pour Mon serveur, j’utilise un socket au lieu d’un
TcpListener. Mais de toute façon le TCPListener utilise un socket sous-jacent,  tout fonctionne bien. En fait mon socket
serveur est en écoute , lorsqu’un client le sollicite, il accept la connexion
sur un autre socket qui  envoie au client
l’information demandée tandis que le socket dédié à l’écoute  reprend son écoute. Tests à l’appui, c’est
tout bon.. Seul le client me pose des problèmes.
 


Cordialement



Philippe
Commenter la réponse de pintux
Messages postés
21
Date d'inscription
mardi 23 juin 2009
Statut
Membre
Dernière intervention
23 juin 2009
0
Merci
Salut Kevin,


D’abord merci pour ton lien, ce code est intéressant. J’ai
procédé de façon très similaire, avec quelques variantes, mais dans l’ensemble
mon serveur est conçu sur ce modèle, qui marche très bien. ; C’est plutôt
la partie cliente qui me fait souffrir, pourtant cela devrait être la plus
simple.


Visiblement le socket client ne peut pas avoir le même
IPEndPoint que le soket serveur, ce qui en terme de client-serveur est une aberration
et même nuit au bon fonctionnement. Preuve en aie que dans le cas contraire,
rien ne fonctionne. Certes, je n’ai plus de message d’erreur, et Visual Studio arrête de m’insulter, alors que c’est plutôt
dans ce cas qu’il devrait m’alerter.


Alors je me pose des questions sur la crédibilité du
framework .NET et de ses outils. J’ajoute que j'ai pu observer des effets de bords de certaines méthodes qui ne sont pa sans conséquences. Par exemple si un socket en écoute accepte une connexion via la méthode Accept(), celà inhibe l'écoute du socket. Ce qui a pour conséquence de satsfaire le premier client qui se connecte, mais pas les suivants; Pour cela il faut repositioner le socket en écoute via la méthode Listen(). Je suis donc un peu déçu par le framework .NET 2.0, et souhaite
que les versions suivantes soient plus abouties.



Cordialement

Philippe
Commenter la réponse de pintux