VB.net приложение для подстановки XMLSocket - PullRequest
0 голосов
/ 20 августа 2010

Я пытаюсь заставить приложение VB.net (экспресс 2010) подключаться к серверу сокетов (оставляя соединение открытым), как бы мне поступить?Сейчас он работает с использованием flash XMLsocket, я пытаюсь создать новый клиент без flash, используя существующий сервер.

В настоящее время я просто использую простое окно для отображения сообщений и место для отправки сообщений.

Он говорит, что я подключен, но не отображает никаких сообщений, и отправленные сообщения, кажется, не имеют никакого эффекта, когда я telnet к серверу, используя тот же 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

1 Ответ

1 голос
/ 20 августа 2010

Пока оба приложения говорят на TCP / IP, одно имеет сокет прослушивающего сервера, а другое знает IP-адрес и номер порта этого сокета и не заблокировано для подключения к нему, не имеет значения, на каком языке в любом приложении написано. Смысл наличия протокола, подобного TCP / IP, заключается в том, что он фактически не зависит от платформы, ОС, инфраструктуры, языка или чего-либо еще.

Что касается вашего кода, выделяются несколько вещей:

  • Вы создаете новый StreamWriter, подключенный к сетевому потоку каждый раз, когда отправляете что-либо. Если средство записи закрывается и удаляется при финализации, что делает большинство IDisposable, он закрывает основной поток (который, в случае потока TcpClient, закроет соединение). Если вы собираетесь использовать средство записи для отправки данных, оставьте его в качестве переменной экземпляра и используйте его повторно, а не каждый раз создавайте новое.

  • Из прочтения о протоколе XmlSocket кажется, что отправленные и полученные строки должны заканчиваться нулем. То есть ваш цикл внутри BuildString должен искать 0, а не 10, когда разбиваете данные на строки, а Send должен добавлять нулевой символ (Chr(0)) вместо vbCr к каждой строке посылает.

  • Вы действительно должны использовать кодировку для преобразования байтов в символы. Ваш существующий код (если он зафиксирован, как указано выше) должен как минимум показывать вам некоторые данные, предполагая, что они должны быть отправлены. Тем не менее, вы можете обнаружить, что данные повреждены из-за предположения, что 1 байт == 1 символ - что редко случается, так как Unicode имеет большой успех. :) Я бы посоветовал вам использовать StreamReader, а не читать напрямую из потока - StreamReader использует закулисную кодировку (UTF-8 по умолчанию, IIRC) и будет обрабатывать большинство мрачных деталей, так что вы не нужно беспокоиться о том, сколько байтов нужно прочитать, чтобы получить символ. Но StreamReaders не имеет встроенного материала для асинхронного чтения. Чтобы использовать 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

(Кстати, комментарии начинаются забавно, так что подсветка синтаксиса действует менее глупо.)

...