Results 1 to 3 of 3

Thread: [RESOLVED] [2008] MSDN Multi-User TCP Chat Sample Thread Broken

  1. #1

    Thread Starter
    New Member
    Join Date
    Jul 2008
    Posts
    7

    Resolved [RESOLVED] [2008] MSDN Multi-User TCP Chat Sample Thread Broken

    Hi All,

    I'm pretty new to VS.NET and trying to get my head around sockets and threading at the min.

    I found a tutorial on the MSDN site that I thought was helpful and I understood what was happening but I've downloaded their code and it doesn't work.

    I had to change a few lines of code to get it to even connect.

    I changed the port number to 5001 (I guess something on my system is already using port 5000).

    I also changed a line of code in SocketServer to be:
    mobjListener = New TcpListener(IPAddress.Any, 5001)

    Whereas before it was just:
    mobjListener = New TcpListener(5001)

    On something connecting, it's now complaining about the update list box being called from a thread other than the one that created it.

    The call to this update is:
    Code:
      Private Sub OnLineReceived(ByVal sender As Client, ByVal Data As String)
        UpdateStatus("Line:" & Data)
    
        Dim objClient As Client
        Dim d As DictionaryEntry
    
        For Each d In mcolClients
          objClient = d.Value
          objClient.Send(Data & vbCrLf)
        Next
      End Sub
    And the procedure it calls is:
    Code:
    Private Sub DisplayText(ByVal t As String)
        txtDisplay.AppendText(t)
      End Sub
    AIUI, We create a new thread in the variable we declared for this, mobjThread and pass it the address of DoListen so the Sub DoListen will run in that thread. We then issue the start command to the thread to start it running.

    We then wait for an incoming connection in this new thread. By running on a new thread, the GUI use is not affected. When a connection is received, we create a new Client and add it to our list of clients.
    We ensure we've added the EventHandlers for this new client so when data is received, we call a sub.
    The data handler that's causing the issue at the minute (I stepped through the code) is OnLineReceived and we declared this as
    Code:
    AddHandler x.LineReceived, AddressOf OnLineReceived
    So, when data is received by the client x, we call OnLineReceived and run the sub.

    Which thread would this be called from? Would it be from the same thread that we created the client in, which was created in the DoListen sub which is running in the mobjThread?

    If so, then obviously it can't be allowed to update Windows Forms from that thread - but why would MSDN show this as an example?

    If I'm right, then this line here:
    Code:
    UpdateStatus("Line:" & Data)
    is what's causing the problem as by calling it from within the OnLineReceived Sub which is running in the mobjThread, it will be also running in the mobjThread.

    I guess I now need to somehow make a DisplayInvoker to marshall that across threads to get it onto the screen - but here I'm stuck.

    I think I've learnt quite a bit about threads and the way VB.NET works so far but not enough to know what to do next.

    Any help would be greatly appreciated - and apologies for the long post!

    I've included all of the code below in case anyone wants to see any other bits.

    Thanks Again,
    Adam


    Code:
    mports System.Threading
    Imports System.Net
    Imports System.Net.Sockets
    
    Public Delegate Sub StatusInvoker(ByVal t As String)
    
    Public Class Form1
      Inherits System.Windows.Forms.Form
    
      Private mobjThread As Thread
      Private mobjListener As TcpListener
      Private mcolClients As New Hashtable()
    
    #Region " Windows Form Designer generated code "
    
      Public Sub New()
        MyBase.New()
    
        'This call is required by the Windows Form Designer.
        InitializeComponent()
    
        'Add any initialization after the InitializeComponent() call
    
      End Sub
    
      'Form overrides dispose to clean up the component list.
      Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
          If Not (components Is Nothing) Then
            components.Dispose()
          End If
        End If
        MyBase.Dispose(disposing)
      End Sub
      Friend WithEvents lstStatus As System.Windows.Forms.ListBox
    
      'Required by the Windows Form Designer
      Private components As System.ComponentModel.Container
    
      'NOTE: The following procedure is required by the Windows Form Designer
      'It can be modified using the Windows Form Designer.  
      'Do not modify it using the code editor.
      <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
            Me.lstStatus = New System.Windows.Forms.ListBox
            Me.SuspendLayout()
            '
            'lstStatus
            '
            Me.lstStatus.Dock = System.Windows.Forms.DockStyle.Fill
            Me.lstStatus.Location = New System.Drawing.Point(0, 0)
            Me.lstStatus.Name = "lstStatus"
            Me.lstStatus.Size = New System.Drawing.Size(292, 264)
            Me.lstStatus.TabIndex = 0
            '
            'Form1
            '
            Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
            Me.ClientSize = New System.Drawing.Size(292, 273)
            Me.Controls.Add(Me.lstStatus)
            Me.Name = "Form1"
            Me.Text = "Socket Server"
            Me.ResumeLayout(False)
    
        End Sub
    
    #End Region
    
      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            mobjThread = New Thread(AddressOf DoListen)
            mobjThread.Start()
        UpdateStatus("Listener started")
      End Sub
    
      Private Sub DoListen()
        Try
                mobjListener = New TcpListener(IPAddress.Any, 5001)
    
          mobjListener.Start()
          Do
            'Dim x As New Client(mobjListener.AcceptSocket)
            Dim x As New Client(mobjListener.AcceptTcpClient)
    
                    AddHandler x.Connected, AddressOf OnConnected
            AddHandler x.Disconnected, AddressOf OnDisconnected
            'AddHandler x.CharsReceived, AddressOf OnCharsReceived
            AddHandler x.LineReceived, AddressOf OnLineReceived
            mcolClients.Add(x.ID, x)
            Dim params() As Object = {"New connection"}
            Me.Invoke(New StatusInvoker(AddressOf Me.UpdateStatus), params)
          Loop Until False
        Catch
        End Try
      End Sub
    
      Private Sub OnConnected(ByVal sender As Client)
            UpdateStatus("Connected")
      End Sub
    
      Private Sub OnDisconnected(ByVal sender As Client)
        UpdateStatus("Disconnected")
        mcolClients.Remove(sender.ID)
      End Sub
    
      'Private Sub OnCharsReceived(ByVal sender As Client, ByVal Data As String)
      '  UpdateStatus("Chars:" & Data)
      'End Sub
    
      Private Sub OnLineReceived(ByVal sender As Client, ByVal Data As String)
        UpdateStatus("Line:" & Data)
    
        Dim objClient As Client
        Dim d As DictionaryEntry
    
        For Each d In mcolClients
          objClient = d.Value
          objClient.Send(Data & vbCrLf)
        Next
      End Sub
    
      Private Sub UpdateStatus(ByVal t As String)
        lstStatus.Items.Add(t)
        lstStatus.SetSelected(lstStatus.Items.Count - 1, True)
      End Sub
    
      Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        mobjListener.Stop()
      End Sub
    End Class

  2. #2
    Raging swede Atheist's Avatar
    Join Date
    Aug 2005
    Location
    Sweden
    Posts
    8,018

    Re: [2008] MSDN Multi-User TCP Chat Sample Thread Broken

    Welcome to the forums.
    Have a look inside your DoListen subroutine, specifically at this line:
    VB.NET Code:
    1. Me.Invoke(New StatusInvoker(AddressOf Me.UpdateStatus), params)
    This will invoke the UpdateStatus method on the UI thread, which is needed.
    But then, in your OnConnected, OnDisconnected and OnLineReceived methods, you are calling UpdateStatus directly. UpdateStatus will therefor be invoked on the worker thread, which gives you the error you're experiencing.
    Rate posts that helped you. I do not reply to PM's with coding questions.
    How to Get Your Questions Answered
    Current project: tunaOS
    Me on.. BitBucket, Google Code, Github (pretty empty)

  3. #3

    Thread Starter
    New Member
    Join Date
    Jul 2008
    Posts
    7

    Re: [2008] MSDN Multi-User TCP Chat Sample Thread Broken

    Thanks - I figured what was wrong but just not how to fix it! It works great now

    Thanks again for your help, I'll mark this thread as resolved now.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width