views:

22

answers:

0

All

I am in the process of prototyping a small sockets application, which monitors IT infrastructure (due to in-house financial and deployment restrictions, I am unable to utilise an existing commercial or open-source solution). Basically, I have a server application and associated agent process for communicating heart-beat data to the server. The server application implements a TCP socket class (TCPDevice), which is called from a WinForm. I am aware of the restriction on updating the UI from processes running on separate threads, and that the preferred technique for acheiving this is via the use of Delegates in conjunction with the Invoke method. Having had very little need previously for using Delegates (apart from of course std windows events and the BackGroundWorker control), I am at a loss as to how to do this in the context of my application, and would appreciate some assistance, although it has occurred to me that I could use the backgroundworker for marshalling updates to the UI.

Eventually the application will need to update a grid of devices via feeds from the defined agents, however for the purpose of this exercise simply updating a status bar on the UI will suffice. The section of the code which I believe is relevant to propogating the code to the form is contained in the OnDataReceived method.

Below is a code excerpt from the protoype app which should put the above into appropriate context:

Code from the form:

Private _device As TcpDevice

Private Sub btnListen_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnListen.Click
        _device = New TcpDevice(uxIPaddress.Text, uxHost.Text, CInt(uxPort.Text))
        _device.Listen()
        Me.btnListen.Enabled = False
End Sub

Code from TCPDevice Class

Public Class TcpDevice : Implements CNIMonitor.Core.Domain.IDevice

    Private _ipAddress As String
    Private _hostName As String
    Private _port As Integer
    Private _status As Integer
    Private _previousStatus As Integer
    Private _listener As TcpListener
    Private _localAdd As System.Net.IPAddress


    Private _activeConnection As TcpClient
    Private _receiveBuffer(0) As Byte
    Private _sendBuffer As Byte
    Private _message As String
    Private _dataRead As Integer 'The value returned from the getstream.endread method


    Public Sub New(ByVal ipAddress As String, ByVal HostName As String, ByVal port As String)
        _ipAddress = ipAddress
        _hostName = HostName
        _port = port
    End Sub

    Public Sub Connect() Implements CNIMonitor.Core.Domain.IDevice.Connect

    End Sub

    Public Sub Disconnect() Implements CNIMonitor.Core.Domain.IDevice.Disconnect

        _activeConnection.Close()
        _listener.Stop()

        _activeConnection = Nothing

    End Sub

    Public Property HostName() As String Implements CNIMonitor.Core.Domain.IDevice.HostName
        Get
            HostName = _hostName
        End Get
        Set(ByVal value As String)
            _hostName = value
        End Set
    End Property

    Public Property IPAddress() As String Implements CNIMonitor.Core.Domain.IDevice.IPAddress
        Get
            IPAddress = _ipAddress
        End Get
        Set(ByVal value As String)
            _ipAddress = value
        End Set
    End Property

    Public Sub Listen() Implements CNIMonitor.Core.Domain.IDevice.Listen
        Try
            'Server component listens on the specified tcpip port
            _localAdd = System.Net.IPAddress.Parse(_ipAddress)
            _listener = New TcpListener(_localAdd, _port)
            _listener.Start()
            _listener.BeginAcceptTcpClient(AddressOf OnClientConnect, _listener)
            'Update the status message                
            Debug.WriteLine("Listening for host " + _ipAddress + " on port " + _port.ToString + ".")
        Catch ex As SocketException
            Debug.WriteLine("Failed listening on " + _ipAddress + " over port " & vbCrLf & " .")
        End Try
    End Sub

    Private Sub OnClientConnect(ByVal ar As IAsyncResult)

        Debug.WriteLine("Received connection from " + ar.AsyncState.ToString)
        'Get the connection object                
        _activeConnection = _listener.EndAcceptTcpClient(ar)
        'on Client connect                
        Debug.WriteLine("Client" + _ipAddress + " connected over port " & vbCrLf & " ." & _port.ToString)
        'Bind the event handler for dealing with incoming data                
        _activeConnection.GetStream.BeginRead(_receiveBuffer, 0, _receiveBuffer.Length, AddressOf onDataReceived, _
            Nothing)
    End Sub

    Private Sub onDataReceived(ByVal ar As IAsyncResult)
        Dim receiveLength As Integer = 0
        ReDim _receiveBuffer(_activeConnection.ReceiveBufferSize - 1)
        Try
            Debug.WriteLine("Receiving from " + _ipAddress + ".")
            ' Complete the BeginReceive() asynchronous call by EndReceive() method                
            ' which will return the number of bytes written to the stream                 
            ' by the client                
            receiveLength = _activeConnection.GetStream.EndRead(ar)
            _message = Encoding.ASCII.GetString(_receiveBuffer, 0, receiveLength)
            _activeConnection.GetStream.BeginRead(_receiveBuffer, 0, _receiveBuffer.Length, AddressOf onDataReceived, Nothing)

            'NOW PASS THE INFORMATION RECEIVED BACK TO THE FORM

        Catch
            Debug.WriteLine("Transmission complete")
        End Try
    End Sub



    Public Property Port() As Integer Implements CNIMonitor.Core.Domain.IDevice.Port
        Get
            Port = _port
        End Get
        Set(ByVal value As Integer)
            _port = value
        End Set
    End Property

    Public Property PreviousStatus() As Integer Implements CNIMonitor.Core.Domain.IDevice.PreviousStatus
        Get
            PreviousStatus = _previousStatus
        End Get
        Set(ByVal value As Integer)
            _previousStatus = value
        End Set
    End Property

    Public Property Status() As Integer Implements CNIMonitor.Core.Domain.IDevice.Status
        Get
            Status = _status
        End Get
        Set(ByVal value As Integer)
            _status = value
        End Set
    End Property


End Class