flash de aplicación sustitución XMLSocket VB.net
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
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, ySend
debe anexar un carácter nulo (Chr(0)
) en lugar de unvbCr
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.)