0

VB.net(express 2010)アプリをソケットサーバーに接続しようとしています(接続を開いたままにします)。これについてはどうすればよいですか?現在、フラッシュXMLsocketを使用して動作します。既存のサーバーを使用して、フラッシュなしで新しいクライアントを構築しようとしています。

現在、私はメッセージを表示するシンプルなウィンドウとメッセージを送信する場所を使用しています。

接続していると表示されますが、メッセージが表示されず、送信されたメッセージは効果がないように見えます。同じIPとポートを使用してサーバーにTelnetで接続すると、メッセージが届くのを確認できるので、接続できることがわかります。サーバーに。これが私のコードです:

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
4

1 に答える 1

1

両方のアプリがTCP/IPを話す限り、一方にはリスニングサーバーソケットがあり、もう一方にはそのサーバーソケットのIPとポート番号がわかっていて、接続がブロックされていない限り、どちらのアプリがどの言語であるかは関係ありません。 TCP / IPのようなプロトコルを持つことのポイントは、それがプラットフォーム、OS、フレームワーク、言語、または他の多くのものか​​ら事実上独立しているということです。

コードに関しては、いくつかの点が際立っています。

  • 何かを送信するたびに、ネットワークストリームに接続された新しいStreamWriterを作成しています。ほとんどのIDisposableが行うように、ライターが閉じてファイナライズ時に自分自身を破棄すると、基になるストリームが閉じられます(TcpClientのストリームの場合は、接続が閉じられます)。ライターを使用してデータを送信する場合は、ライターをインスタンス変数として保持し、毎回新しいライターを作成するのではなく、再利用します。

  • XmlSocketプロトコルについて読んだところ、送受信された文字列はnullで終了する必要があるようです。つまり、内部のループはBuildString、データを文字列に分割するときに10ではなく0を探し、送信するすべての文字列にaではなくSendヌル文字()を追加する必要があります。Chr(0)vbCr

  • 実際には、エンコーディングを使用してバイトを文字に変換する必要があります。既存のコード(上記のように修正された場合)は、送信されるデータがあると仮定して、少なくともいくつかのデータを表示する必要があります。ただし、1バイト== 1文字であるという仮定のために、データが破損していることに気付くかもしれません。これは、Unicodeが大きな打撃を与えたため、めったにありません。:)ストリームから直接読み取るのではなく、StreamReaderを使用することをお勧めします-StreamReaderは舞台裏でエンコーディング(デフォルトではUTF-8、IIRC)を使用し、厄介な詳細のほとんどを処理するため、文字を取得するために読み取るバイト数について心配する必要はありません。ただし、StreamReaderには、非同期読み取りを行うための機能が組み込まれていません。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

(ところで、コメントは面白く始められているので、構文の強調表示はそれほど愚かではありません。)

于 2010-08-20T03:07:54.790 に答える