Domanda

Sto cercando di ottenere un VB.net (Express 2010) all'applicazione di connettersi a un server socket (mantenendo il collegamento aperto), come potrei fare per questo? In questo momento funziona utilizzando il flash XMLSocket, sto cercando di costruire un nuovo cliente senza flash, utilizzando il server esistente.

Al momento sto solo utilizzando una finestra semplice la visualizzazione di messaggi, e un posto per inviare messaggi.

Si dice che sono connesso, ma visualizza nessun messaggio, e ha inviato messaggi sembrano avere alcun effetto, quando ho telnet al server utilizzando lo stesso IP e la porta, posso vedere i messaggi in arrivo per me, quindi so posso collegarmi al server. Ecco il mio codice:

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
È stato utile?

Soluzione

Fino a quando entrambe le applicazioni parlano TCP / IP, si ha un socket server in ascolto, e l'altro conosce il numero IP e la porta di quel socket server e non è bloccato e si collega ad esso, non importa quale lingua o applicazione è scritta in. Il punto di avere un protocollo come TCP / IP è che è effettivamente indipendente da piattaforma, sistema operativo, quadro, la lingua, o molto più di qualsiasi altra cosa.

Per quanto riguarda il codice, alcune cose si distinguono:

  • Si sta creando un nuovo StreamWriter collegata al flusso di rete ogni volta che si invia nulla. Se si chiude scrittore e si dispone su finalizzazione, che la maggior parte IDisposables fanno, sarebbe chiudere il flusso sottostante (che, nel caso di trasmissione del TcpClient, chiuderà la connessione). Se avete intenzione di utilizzare uno scrittore per inviare i dati, tenere uno come una variabile di istanza e riutilizzarla piuttosto che crearne uno nuovo ogni volta.

  • Dalla lettura sul protocollo XMLSocket, sembra che le corde inviati e ricevuti dovrebbe essere terminata da null. Cioè, il ciclo all'interno BuildString dovrebbe essere alla ricerca di 0 piuttosto che 10 quando si rompe il backup dei dati in stringhe, e Send va aggiungendo un carattere nul (Chr(0)) piuttosto che un vbCr ad ogni stringa che invia.

  • Si dovrebbe utilizzare una codifica per convertire i byte a caratteri. Il tuo codice esistente (se fisso come sopra) dovrebbe almeno mostrare alcuni dati, supponendo che ci sia alcun da inviare. Si può anche trovare i dati danneggiati, anche se, a causa del presupposto che 1 byte == 1 carattere - che è raramente il caso in quanto Unicode colpito in grande. :) Io suggerirei di usare uno StreamReader piuttosto che leggere direttamente dal flusso - lo StreamReader utilizza una codifica dietro le quinte (UTF-8 uno per impostazione predefinita, IIRC), e consente di gestire la maggior parte dei dettagli scabrosi, in modo da non è necessario preoccuparsi di quanti byte da leggere per ottenere un char. Ma StreamReaders non hanno la roba integrato in loro di fare asincrona legge. Dovreste cambiare la vostra roba un po ', e genera un thread per esso, al fine di utilizzare uno StreamReader.

È possibile utilizzare un decoder direttamente, che è praticamente quello che uno StreamReader fa. Usalo qualcosa di simile:

''// 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

(a proposito, i commenti sono iniziato divertente in modo che l'evidenziazione della sintassi agisce meno stupido.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top