-
Apr 17th, 2012, 02:31 AM
#1
[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
-
Apr 19th, 2012, 11:45 PM
#2
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|