سؤال

أحاول الحصول على تطبيق VB.NET (Express 2010) للاتصال بخادم المقبس (الحفاظ على اتصال الاتصال) ، كيف يمكنني القيام بذلك؟ يعمل الآن باستخدام Flash XMLSocket ، أحاول إنشاء عميل جديد بدون فلاش ، باستخدام الخادم الموجود.

حاليًا أنا فقط أستخدم نافذة بسيطة تعرض الرسائل ، ومكان لإرسال الرسائل.

يقول إنني متصل ، لكنه لا يعرض أي رسائل ، ويبدو أن الرسائل المرسلة ليس لها أي تأثير ، عندما أقوم بالتواصل مع الخادم باستخدام نفس 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 جديدة متصلة بتيار الشبكة في كل مرة ترسل فيها أي شيء. إذا أغلق الكاتب ويتصرف على الانتهاء ، وهو ما يفعله معظم diSposables ، فسيتم إغلاق الدفق الأساسي (الذي سيغلق الاتصال ، في حالة تيار TCPClient). إذا كنت ستستخدم كاتبًا لإرسال البيانات ، فاحرص على ذلك كمتغير مثيل وأعد استخدامه بدلاً من إنشاء واحدة جديدة في كل مرة.

  • من القراءة حول بروتوكول XMLSOCKET ، يبدو أن الأوتار المرسلة والمستلمة يجب أن تتم إنهاء الفرق. هذا هو ، حلقة الخاص بك في الداخل BuildString يجب أن تبحث عن 0 بدلاً من 10 عند تقسيم البيانات إلى سلاسل ، و Send يجب أن تُلحق شخصية NUL (Chr(0)) بدلا من vbCr إلى كل سلسلة يرسلها.

  • يجب أن تستخدم حقًا ترميزًا لتحويل البايتات إلى chars. يجب أن يظهر لك الرمز الحالي (عند إصلاحه على النحو الوارد أعلاه) بعض البيانات على الأقل ، على افتراض أنه سيتم إرسال أي شيء. يمكنك العثور على البيانات تالفة ، بسبب افتراض أن 1 بايت == 1 char - وهو ما هو نادرا ما هو الحال منذ أن ضربها Unicode بشكل كبير. :) أقترح عليك استخدام StreamReader بدلاً من القراءة مباشرة من الدفق-يستخدم StreamReader ترميزًا خلف الكوالي لا داعي للقلق بشأن عدد البايتات التي يجب قراءتها للحصول على شار. ولكن لا يملك Streamreaders الأشياء المدمجة فيها للقيام بقراءات 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

(راجع للشغل ، بدأت التعليقات مضحكة بحيث يتصرف بناء الجملة الذي يبرز أقل غباء.)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top