Vb.net flash xmlsocket Замена приложения
Вопрос
Я пытаюсь получить приложение VB.Net (Express 2010) для подключения к серверу сокета (сохраняя открытое соединение), как бы я поступил в это? Прямо сейчас он работает с помощью Flash XMLSocket, я пытаюсь построить новый клиент без Flash, используя существующий сервер.
В настоящее время я просто использую простое окно, отображающее сообщения, а также место для отправки сообщений.
Он говорит, что я подключен, но не отображается никаких сообщений, и отправленные сообщения не имеют никакого эффекта, когда я телнет на сервер, используя тот же IP и порт, я могу видеть сообщения, приходящие для меня, поэтому я знаю, что могу подключиться на сервер. Вот мой код:
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
Решение
До тех пор, пока оба приложения говорят TCP / IP, у одного есть сокет сервера прослушивания, а другой знает номер IP и порта этого сокета сервера и не блокируется от подключения к нему, не имеет значения, на каком языке либо приложение написано. Точка имела протокол, такой как TCP / IP, заключается в том, что он эффективно не зависит от платформы, ОС, рамки, языка или многое другое.
Что касается вашего кода, выделяются несколько вещей:
Вы создаете новый Streamwriter, прикрепленный к сетевому потоку каждый раз, когда вы отправляете что-либо. Если писатель закрывается и утилизируется на завершение, что большинство IDSPLABLES делают, он закроет основной поток (который, в случае потока TCPClient, закроет соединение). Если вы собираетесь использовать писатель для отправки данных, сохраняйте один в качестве переменной экземпляра и повторно используйте его, а не создавать новый каждый раз.
От чтения про протокола XMLSocket, кажется, что строки, отправленные и полученные должны быть расторгнутыми в нуле. То есть ваша петля внутри
BuildString
следует искать 0, а не 10 при расстановке данных на строки, а такжеSend
должно быть добавление персонажа Nul (Chr(0)
), а не чемvbCr
к каждой строке, которую он отправляет.Вы действительно должны использовать кодировку для преобразования байтов для Chars. Ваш существующий код (при исправлении, как указано выше), должен, по крайней мере, покажет вам некоторые данные, предполагая, что есть какие-либо отправляемые. Вы вполне можете найти поврежденные данные, однако из-за предположения, что 1 байт == 1 CHAR - что редко бывает случай, поскольку Unicode ударил его большим. :) Я бы предложил, чтобы вы использовали StreameReader, а не чтение непосредственно из потока - Streamreader использует кодировку за кулисами (UTF-8 по умолчанию, IIRC), и будет справиться с большинством деталей горы, так что вы Не нужно беспокоиться о том, сколько байтов читать, чтобы получить чар. Но упрочны не имеют встроенных в них вещей, чтобы сделать async читать. Вам нужно немного менять свои вещи и порождать нить для него, чтобы использовать Streamreader.
Вы можете использовать декодер напрямую, что в значительной степени то, что делает Streamreader. Используйте его что-то вроде этого:
''// 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
(Кстати, комментарии начинаются смешно, так что подсветка синтаксиса действует менее глупым.)