Results 1 to 2 of 2

Thread: [VB2008] Asynchronous TcpClient

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    [VB2008] Asynchronous TcpClient

    I've finally dipped my toes into .Net and created the following with the assistance of quite a few examples I found lying around the Internet.

    It's a simple 'text exchanger' between it and a Server and is designed to run on a Pocket PC using Compact Framework 2 which appears to work. (I have a simple 'echo' server for testing, that just sends back anything it receives). It will also run as a 'standard' windows application.

    As a "VB6'er" I've not been used to managing communications between different threads (and have been 'spoilt' by Winsock) so that's the main area where improvements could, perhaps, be made. Also, there may be 'VB6 style code' where .Net would do it 'better'.

    I've included comments identifying areas where I'm not too sure. Any advice / comments / criticisms (constructive) for improvement would be gratefully received. This is really meant to be a proof of concept / model for a larger application so I'd like to do it 'properly'.
    Code:
    Imports System.Net.Sockets
    Imports System.Text
    
    Public Class Form1
        Dim Client As New TcpClient
        Dim state As New StateObject
        Public Delegate Sub DataReceived()
    
        Private Sub UpdateText()
            '
            ' (Invoked by the Deligate Sub DataReceived)
            ' If this was other than a simple text swapping application
            ' this is where the data would be buffered until a 'record complete'
            ' character had been received
            '
            txtReceived.Text = txtReceived.Text & result & vbNewLine
        End Sub
    
        Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.Click
            Dim Err As Boolean = False
            state.workClient = Client
            Dim Error_Message As String = "Error: "
            '
            ' Do some simple validation of the Host and Port
            '
            If txtHost.Text = "" Then
                Error_Message = Error_Message & "Host not Specified" & vbNewLine
                Err = True
            End If
            '
            ' TODO: check that the Port is numeric and in an appropriate range
            '
            If txtPort.Text = "" Then
                Error_Message = Error_Message & "Port not Specified" & vbNewLine
                Err = True
            End If
            If Not Err Then
                Try
                    '
                    ' Use a blocking connection request
                    ' since nothing can happen until we're connected
                    '
                    Client.Connect(txtHost.Text, CInt(txtPort.Text))
                    '
                    ' Connected OK
                    ' Set the UI appropriately
                    ' and start an asynchronous read
                    '
                    btnSend.Enabled = True
                    btnConnect.Enabled = False
                    'MsgBox("Connected")
                    Call Receive(Client)
                Catch ex As Exception
                    MsgBox("Unable to Connect: " & ex.Message)
                    '
                    ' Is this the correct way to gracefully terminate ?
                    '
                    Application.Exit()
                End Try
            Else
                MsgBox(Error_Message)
            End If
        End Sub
    
        Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
            '
            ' Check there's something to send and send it asynchronously
            '
            ' TODO: Put in a Try / Catch block and determine what to do
            ' in the event of an exception
            '
            If txtToSend.Text <> "" Then
                '
                ' Is this the most efficient method to use to convert the
                ' string data to a binary array ?
                ' (It feels a bit "VB6'ish")
                '
                Dim bytSend(txtToSend.TextLength - 1) As Byte
                For i = 0 To txtToSend.TextLength - 1
                    bytSend(i) = Asc(txtToSend.Text.Substring(i, 1))
                Next
                Client.Client.BeginSend(bytSend, 0, txtToSend.TextLength, 0, AddressOf SendCallback, Client)
            End If
        End Sub
    
        Private Sub SendCallback(ByVal ar As IAsyncResult)
            '
            ' I guess I could check to ensure that all bytes 
            ' have been sent by examining the return from EndSend(?)
            '
            Client.Client.EndSend(ar)
        End Sub
    
        Private Sub Receive(ByVal rClient As TcpClient)
            '
            ' Fire off a receive and let the CallBack routine do its work
            '
            Dim state As New StateObject
            Try
                state.workClient = rClient
                rClient.Client.BeginReceive(state.buffer, 0, state.BufferSize, 0, AddressOf ReceiveCallBack, state)
            Catch ex As Exception
                '
                ' TODO: Analyse the exception to determine if it's recoverable
                ' and take appropriate action
                '
                MsgBox("Receive Error " & ex.Message)
            End Try
        End Sub
    
        Private Sub ReceiveCallBack(ByVal ar As IAsyncResult)
            '
            ' Something's ready to be received
            ' get hold of it and use the Deligate (DataReceived) to update the UI Thread
            ' using the UpdateText routine
            '
            Try
                Dim state As StateObject = CType(ar.AsyncState, StateObject)
                '
                ' Flush the buffer 
                '
                state.sb.Length = 0
                '
                ' Pick up the Client Object, determine the amount of data received
                ' and convert it to a string. 
                ' (The variable 'result' is defined as Public in a Module - I guess I could
                ' just pass it as a ByVal parameter to UpdateText instead or could it be a member
                ' of the StateObject ?)
                '
                Dim rClient As TcpClient = state.workClient
                Dim bytesRead As Integer = rClient.Client.EndReceive(ar)
                If bytesRead > 0 Then
                    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead))
                    result = state.sb.ToString
                    BeginInvoke(New DataReceived(AddressOf UpdateText))
                    '
                    ' Start another asynchronous read
                    '
                    rClient.Client.BeginReceive(state.buffer, 0, state.BufferSize, 0, AddressOf ReceiveCallBack, state)
                End If
            Catch ex As Exception
                '
                ' TODO: Analyse the exception to determine if it's recoverable
                ' and take appropriate action
                '
                MsgBox("Error in ReceiveCallBack: " & ex.Message)
            End Try
        End Sub
    
    Public Class StateObject
        Public workClient As TcpClient = Nothing
        Public BufferSize As Integer = 256
        Public buffer(255) As Byte
        Public sb As New StringBuilder()
    End Class
    Last edited by Doogle; Apr 17th, 2012 at 03:41 AM. Reason: Added some more comments

  2. #2

    Thread Starter
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: [VB2008] Asynchronous TcpClient

    Well, I guess there's no 'glaring' issues so I'll just plod on and see what happens. Thanks to all who read this.

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