【问题标题】:VB.net flash XMLSocket substitution appVB.net flash XMLSocket 替换应用程序
【发布时间】:2011-04-01 11:09:53
【问题描述】:

我正在尝试让 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

【问题讨论】:

  • Nitpick:客户端通常连接到服务器,而不是相反。 FTP 之类的协议例外,它允许服务器打开辅助套接字进行数据传输。
  • XmlSocket 部分似乎特别相关,因为它定义了使用的协议,但远程服务器的语言/平台并不重要。不过,它确实增加了您应该使用像 UTF-8 这样的编码来解码字符串的论点,而不是仅仅假设每个字节都是一个字符(现在很少出现这种情况了)。

标签: vb.net sockets xmlsocket


【解决方案1】:

只要两个应用程序都使用 TCP/IP,一个具有侦听服务器套接字,另一个知道该服务器套接字的 IP 和端口号并且没有被阻止连接到它,不管是什么语言任何一个应用程序都是编写的。拥有像 TCP/IP 这样的协议的关键在于它实际上独立于平台、操作系统、框架、语言或其他任何东西。

至于你的代码,有几点很突出:

  • 每次发送任何内容时,您都会创建一个附加到网络流的新 StreamWriter。如果编写器关闭并在完成时自行处置,大多数 IDisposables 都会这样做,它将关闭基础流(在 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

(顺便说一句,cmets 开始很有趣,因此语法突出显示的行为不那么愚蠢。)

【讨论】:

  • 是的,我理解那部分,我需要的是能够做到这一点的visual basic.net的cosing(客户端,而不是服务器),我可以自己解析它一旦我能得到数据。
  • 有效!太感谢了!一旦我知道它有效,我就会接受这个答案。
  • 我将如何使用编码?对不起!
  • 嗯...我将使用什么编码来实现 StreamReader?
  • 嗯。我认为它会更干净,但忘记了 BeginRead/EndRead 的东西。您可以想象使用委托和 BeginInvoke/EndInvoke,或将其传递给 ThreadPool.QueueUserWorkItem,来完成类似的事情。
猜你喜欢
  • 2011-05-11
  • 2013-07-25
  • 1970-01-01
  • 2011-07-14
  • 2012-06-10
  • 1970-01-01
  • 1970-01-01
  • 2011-12-18
  • 1970-01-01
相关资源
最近更新 更多