Question

Je suis en train d'obtenir un VB.net (express 2010) application de se connecter à un serveur socket (en gardant l'ouverture de connexion), comment pourrais-je aller à ce sujet? En ce moment, il fonctionne à l'aide xmlsocket flash, je suis en train de construire un nouveau client sans flash, en utilisant le serveur existant.

Actuellement, je suis juste en utilisant une fenêtre simple, l'affichage des messages, et un endroit pour envoyer des messages.

Il dit que je suis connecté, mais il affiche aucun message, et les messages envoyés semblent avoir aucun effet, quand je telnet au serveur en utilisant la même adresse IP et le port, je peux voir les messages à venir pour moi, donc je sais Je peux vous connecter au serveur. Voici mon code:

Imports System.Text
Imports System.Net.Sockets


Public Class Form1
    Inherits System.Windows.Forms.Form

    Public Delegate Sub DisplayInvoker(ByVal t As String)

    Private mobjClient As TcpClient
    Private marData(1024) As Byte
    Private mobjText As New StringBuilder()

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        mobjClient = New TcpClient("example.com", 7777)
        DisplayText("Connected to host " & "example.com")

        mobjClient.GetStream.BeginRead(marData, 0, 1024, AddressOf DoRead, Nothing)
    End Sub

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        Send(txtSend.Text)
        txtSend.Text = ""
    End Sub

    Private Sub Send(ByVal t As String)
        Dim w As New IO.StreamWriter(mobjClient.GetStream)
        w.Write(t & vbCr)
        w.Flush()
        DisplayText(vbNewLine & "Sent " & t)
    End Sub

    Private Sub DoRead(ByVal ar As IAsyncResult)
        Dim intCount As Integer
        Try
            intCount = mobjClient.GetStream.EndRead(ar)
            If intCount < 1 Then
                MarkAsDisconnected()
                Exit Sub
            End If

            BuildString(marData, 0, intCount)

            mobjClient.GetStream.BeginRead(marData, 0, 1024, AddressOf DoRead, Nothing)
        Catch e As Exception
            MarkAsDisconnected()
        End Try
    End Sub

    Private Sub BuildString(ByVal Bytes() As Byte, ByVal offset As Integer, ByVal count As Integer)
        Dim intIndex As Integer

        For intIndex = offset To offset + count - 1
            If Bytes(intIndex) = 10 Then
                mobjText.Append(vbLf)

                Dim params() As Object = {mobjText.ToString}
                Me.Invoke(New DisplayInvoker(AddressOf Me.DisplayText), params)

                mobjText = New StringBuilder()
            Else
                mobjText.Append(ChrW(Bytes(intIndex)))
            End If
        Next
    End Sub

    Private Sub MarkAsDisconnected()
        txtSend.ReadOnly = True
        btnSend.Enabled = False
        DisplayText(vbNewLine & "Dissconnected")
    End Sub

    Private Sub DisplayText(ByVal t As String)
        txtDisplay.AppendText(t)
    End Sub
End Class
Était-ce utile?

La solution

Tant que les applications parlent TCP / IP, on a un socket serveur d'écoute, et l'autre connaît le numéro IP et le port de cette socket serveur et n'est pas bloqué de se connecter à lui, il n'a pas d'importance quelle langue soit l'application est écrit. Le point d'avoir un protocole comme TCP / IP est qu'il est effectivement indépendant de la plate-forme, système d'exploitation, le cadre, la langue, ou quoi que ce soit d'autre.

En ce qui concerne votre code, quelques choses ressortent:

  • Vous créez un nouveau StreamWriter attaché au flux réseau chaque fois que vous envoyez quoi que ce soit. Si l'écrivain ferme et se dispose sur la finalisation, que la plupart IDisposables font, il serait fermer le flux sous-jacent (qui, dans le cas du flux du TcpClient, fermera la connexion). Si vous allez utiliser un écrivain pour envoyer des données, garder un comme une variable d'instance et le réutiliser plutôt que de créer un nouveau à chaque fois.

  • De la lecture sur le protocole xmlsocket, il semble que les chaînes envoyées et reçues doivent être serties nulle. C'est, votre boucle à l'intérieur BuildString devrait rechercher 0 au lieu de 10 lors de la rupture des données en chaînes et Send doit être annexant un caractère NUL (de Chr(0)) plutôt que d'un vbCr à chaque chaîne envoie.

  • Vous devriez vraiment utiliser un encodage pour convertir les octets à caractères. Votre code existant (lorsqu'il est fixé comme ci-dessus) devrait au moins vous montrer certaines données, en supposant qu'il y ait à envoyer. Vous pouvez ainsi trouver les données corrompues, cependant, en raison de l'hypothèse selon laquelle 1 octet == 1 caractère - ce qui est rarement le cas depuis Unicode a frappé le gros lot. :) Je vous suggère d'utiliser un StreamReader plutôt que de lire directement à partir du flux - StreamReader utilise un codage dans les coulisses (UTF-8, un par défaut, IIRC), et traitera la plupart des détails sordides, de sorte que vous ne pas à vous soucier de combien d'octets à lire pour obtenir char. Mais StreamReaders n'ont pas les choses construit en eux pour faire lit async. Il faudrait changer vos trucs un peu, et frayer un fil pour elle, afin d'utiliser un StreamReader.

Vous pouvez utiliser un décodeur directement, ce qui est à peu près ce qu'un StreamReader fait. Utilisez quelque chose comme ceci:

''// This is important!  Keep the Decoder and reuse it when you read this socket.
''// If you don't, a char split across two reads will break.
Private _decoder As Decoder = UTF8Encoding.GetDecoder()


Private Sub BuildString(bytes() As Byte, offset As Integer, byteCount As Integer)

    ''// Here's where the magic happens.  The decoder converts bytes into chars.
    ''// But it remembers the final byte(s), and doesn't convert them,
    ''// until they form a complete char.
    Dim chars(bytes.Length) As Char
    Dim charCount as Integer = _decoder.GetChars(bytes, offset, byteCount, chars, 0)

    For i as Integer = 0 to charCount - 1
        if chars(i) = chr(0) then           ''// The fix for bullet #2
            mObjText.Append(vbLf)

            Dim params() As Object = {mobjText.ToString}
            Me.Invoke(New DisplayInvoker(AddressOf Me.DisplayText), params)

            ''// You don't have to make a new StringBuilder, BTW -- just clear it.
            mObjText.Length = 0
        else
            mObjText.Append(chars(i))
        end if
    Next
End Sub

(BTW, les commentaires sont démarrés drôle de sorte que la mise en évidence de la syntaxe agit moins stupide.)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top