Pregunta

Estoy intentando conseguir un VB.net (Express 2010) aplicación se conecte a un servidor de socket (manteniendo la conexión abierta), ¿cómo iba a ir sobre esto? En este momento funciona usando xmlsocket flash, estoy tratando de construir un nuevo cliente sin flash, usando el servidor existente.

Actualmente estoy usando una simple ventana que muestra los mensajes, y un lugar para enviar mensajes.

Se dice que estoy conectado, pero que no muestra mensajes y envía mensajes parecen tener ningún efecto, cuando telnet al servidor utilizando la misma IP y el puerto, puedo ver los mensajes que viene a mí, así que sé puedo conectar con el servidor. Aquí está mi código:

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
¿Fue útil?

Solución

Mientras tanto hablan aplicaciones TCP / IP, uno tiene un socket de servidor escucha, y el otro sabe el número IP y el puerto de ese zócalo del servidor y no está bloqueado y no podrá conectarse a ella, no importa qué idioma o bien la aplicación está escrita en. El punto de tener un protocolo como TCP / IP es que es efectivamente independiente de la plataforma, sistema operativo, el marco, el idioma, o casi nada más.

En cuanto a su código, algunas cosas que se destacan:

  • Estás creando un nuevo StreamWriter unido a la corriente de la red cada vez que envía nada. Si se cierra el escritor y dispone a sí mismo en la mayoría de finalización, que hacen IDisposables, que cerrará la corriente subyacente (que, en el caso de la corriente del TcpClient, se cerrará la conexión). Si vas a usar un escritor para enviar datos, mantener una como una variable de instancia y volver a utilizarlo en lugar de crear uno nuevo cada vez.

  • A partir de la lectura sobre el protocolo xmlsocket, parece que las cadenas enviados y recibidos debe ser terminada en nulo. Es decir, el bucle interior BuildString debe estar buscando 0 en lugar de 10 al romper los datos en cadenas, y Send debe anexar un carácter nulo (Chr(0)) en lugar de un vbCr a cada cuerda que envía.

  • Usted realmente debe utilizar una codificación para convertir los bytes de caracteres. Su código existente (cuando se fija como arriba) debería al menos mostrar algunos datos, suponiendo que haya ninguna para ser enviados. Usted también puede encontrar los datos dañado, sin embargo, debido a la suposición de que 1 byte == 1 carácter - que raramente es el caso, ya que Unicode dispara grande. :) me gustaría sugerir que utilice un StreamReader en lugar de leer directamente de la corriente - el StreamReader utiliza una codificación detrás de las escenas (la codificación UTF-8, uno por defecto, IIRC), y se encargará de la mayor parte de los detalles morbosos, por lo que no es necesario preocuparse por la cantidad de bytes a leer para obtener un carbón de leña. Pero StreamReaders no tienen el material incorporado en ellos para hacer asíncrono lee. Habría que cambiar sus cosas un poco, y generará un subproceso para ello, con el fin de utilizar un StreamReader.

Se puede usar un decodificador directamente, lo que es más o menos lo que hace un StreamReader. Utilizarlo algo como esto:

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

(Por cierto, los comentarios se inician divertida para que el resaltado de sintaxis actúa menos estúpidos.)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top