Chapter 15 (Communications) Samples
Listing 15.1. Trivial File I/O Code That Notes Local vs. Server Differences This is just a series of function calls. It should be easy for VB programmers to follow the C# code.Listing 15.2. Simulating Communications Failure to Test Your Application
'Conditional compile flags for our insturmented code #Const DEBUG_SIMULATE_FAILURES = 1 'Simulate failures '#Const DEBUG_SIMULATE_FAILURES = 0 'Don't simulate failures '------------------------------------------------------------- 'A global variable we want to use to indicate that we 'should throw an exception during communications '------------------------------------------------------------- #If DEBUG_SIMULATE_FAILURES <> 0 Then 'Variable that holds next pending failure Shared g_failureCode As SimulatedFailures = _ SimulatedFailures.noFailurePending 'List of failures that we want to simulate public enum SimulatedFailures noFailurePending 'No test failures pending 'Simulated failures: failInNextWriteSocketCode failInNextWebServiceCall failInNextFileIODuringFileOpen failInNextFileIODuringFileRead 'etc. End Enum #End If 'DEBUG_SIMULATE_FAILURES '------------------------------------------------------------- 'The function we import to communicate data. '------------------------------------------------------------- Private Sub writeDataToSocket( _ ByVal mySocket As System.Net.Sockets.Socket, _ ByVal dataToSend() As Byte) '------------------------------------------------------------ 'Only compile this code in if we are testing network failures '------------------------------------------------------------ #If DEBUG_SIMULATE_FAILURES <> 0 Then 'If this is the failure we want to test, throw an Exception If (g_failureCode = _ SimulatedFailures.failInNextWriteSocketCode) Then 'Reset the failure so it does not occur next time 'this function is called g_failureCode = SimulatedFailures.noFailurePending Throw New Exception("Test communications failure: " + _ g_failureCode.ToString()) End If #End If 'Send the data as normal. mySocket.Send(dataToSend) End Sub
Listing 15.3. Test Code to Go Inside a Form Class to Test IrDA Transmit and Receive
'The name we want to give to our IrDA socket Const myIrDASocketName As String = "IrDaTestFileTransmit" Private Sub buttonTestFileSend_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles buttonTestFileSend.Click 'Create a simple text file we want to send Const fileName As String = "\myTestSendFile.txt" Dim textFileStream As System.IO.StreamWriter textFileStream = System.IO.File.CreateText(fileName) textFileStream.WriteLine("Today...") textFileStream.WriteLine("is a nice day") textFileStream.WriteLine("to go swim") textFileStream.WriteLine("in the lake") textFileStream.Close() Dim irdaFileSender As IrDAFileSend irdaFileSender = New IrDAFileSend(fileName, myIrDASocketName) 'We have 2 options: 1 - Sync, 2 - Async '1. Call the function synchronously 'and block the thread until the 'file is sent '1a. Let the user know we're waiting to send Me.Text = "Trying to send..." ' '1b. Wait until we find a client and then send the file irdaFileSender.LoopAndAttemptIRSend() '1c. Let the user know the file has been transmitted MsgBox("File sent!") Me.Text = "IrDA: Sent!" '2. Call the function async and set 'up a background thread to do the sending 'irdaFileSend.LoopAndAttemptIRSendAsync() 'NOTE: If we call the function async, we want to 'occasionally check if it is finished by 'calling 'irdaFileSend.Status' End Sub Private Sub buttonTestFileReceive_Click(ByVal sender As Object _ , ByVal e As EventArgs) Handles buttonTestFileReceive.Click 'If our destination file exists, delete it Const fileName As String = "\myTestReceiveFile.txt" If (System.IO.File.Exists(fileName)) Then System.IO.File.Delete(fileName) End If Dim irdaFileReceiver As IrDAFileReceive irdaFileReceiver = New IrDAFileReceive(fileName, _ myIrDASocketName) 'We have 2 options: 1 - Sync, 2 - Async '1. Call the function synchronously 'and block the thread until the 'file is received '1a. Let the user know we're waiting to receive Me.Text = "Waiting to receive..." '1b. Wait until someone contacts us and sends the file irdaFileReceiver.WaitForIRFileDownload() '1c. Let the user know we've got the sent file Me.Text = "IrDA: received!" MsgBox("File received!") '2. Call the function async and set 'up a background thread to do the receive 'irdaFileReceive.WaitForIRFileDownloadAsync() 'NOTE: If we call the function async, we want to 'occasionally check if it is finished by 'calling 'irdaFileReceive.Status' End Sub
Listing 15.4. IrDAFileSend Class
Option Strict On '============================================================= 'This class is an IrDA client. It looks for an IrDA 'server with a matching IrDA service name and when found 'it streams the data of a file to it. '============================================================= Class IrDAFileSend Private m_descriptionOfLastSendAttempt As String Private m_IrDAServiceName As String Private m_fileToSend As String Private m_wasSenderStopped As Boolean Public Enum SendStatus AttemptingToSend Finished_Successfully Finished_Aborted Finished_Error End Enum Private m_SendStatus As SendStatus Public ReadOnly Property Status() As SendStatus Get 'Lock prevents concurrent read/write to m_SendStatus SyncLock (Me) Return m_SendStatus End SyncLock End Get End Property Private Sub setStatus(ByVal newStatus As SendStatus) 'Lock prevents concurrent read/write to m_SendStatus SyncLock (Me) m_SendStatus = newStatus End SyncLock End Sub Public ReadOnly Property ErrorText() As String Get Return m_descriptionOfLastSendAttempt End Get End Property '------------------------------------------------------------ 'CONSTRUCTOR '------------------------------------------------------------ Public Sub New(ByVal fileToSend As String, _ ByVal irdaServiceName As String) 'The name of the IrDA socket we want to look for m_IrDAServiceName = irdaServiceName 'The file we want to send m_fileToSend = fileToSend End Sub '------------------------------------------------------------- 'Starts a new thread to try to send the file '------------------------------------------------------------- Public Sub LoopAndAttemptIRSendAsync() 'We are in send mode setStatus(SendStatus.AttemptingToSend) 'User has not aborted us yet m_wasSenderStopped = False 'This is the function we want the new thread to start running Dim threadEntryPoint As System.Threading.ThreadStart threadEntryPoint = _ New System.Threading.ThreadStart(AddressOf _ LoopAndAttemptIRSend) '-------------------------------------------- 'Create a new thread and start it running '-------------------------------------------- Dim newThread As System.Threading.Thread = _ New System.Threading.Thread(threadEntryPoint) newThread.Start() 'Go! End Sub '------------------------------------------------------------- 'Goes in loops and tries to send the file via IR '------------------------------------------------------------- Public Sub LoopAndAttemptIRSend() Dim irDASender As System.Net.Sockets.IrDAClient Dim streamOutToIrDA As System.IO.Stream Dim streamInFromFile As System.IO.Stream 'User has not aborted us yet m_wasSenderStopped = False setStatus(SendStatus.AttemptingToSend) '------------------------------------------------------------ 'Continually loop and try to send the message until '------------------------------------------------------------ While (True) 'These should all be null going in and out of the ''sendStream(...)' call unless an exception is thrown! irDASender = Nothing streamOutToIrDA = Nothing streamInFromFile = Nothing 'Attempt to send the stream Dim bSuccess As Boolean Try bSuccess = sendStream(m_descriptionOfLastSendAttempt, _ streamOutToIrDA, irDASender, streamInFromFile) Catch eUnexpected As System.Exception 'Unexpected error!!! setStatus(SendStatus.Finished_Error) 'Note the failure m_descriptionOfLastSendAttempt = _ "Unexpected error in IR send loop. " + eUnexpected.Message '--------------------------------------------------- 'Clean up any resources we may have allocated '--------------------------------------------------- If Not (streamOutToIrDA Is Nothing) Then Try streamOutToIrDA.Close() Catch 'Swallow any error End Try streamOutToIrDA = Nothing End If If Not (streamInFromFile Is Nothing) Then Try streamInFromFile.Close() Catch 'Swallow any error End Try streamInFromFile = Nothing End If If Not (irDASender Is Nothing) Then Try irDASender.Close() Catch 'Swallow any error End Try irDASender = Nothing End If Return 'Exit End Try 'See if we succeeded If (bSuccess = True) Then m_descriptionOfLastSendAttempt = "Success!" setStatus(SendStatus.Finished_Successfully) Return End If 'See if there was a user-driven abort If (m_wasSenderStopped = True) Then m_descriptionOfLastSendAttempt = "User Aborted." setStatus(SendStatus.Finished_Aborted) Return End If 'Otherwise ... We have not found an IrDA server with a 'matching service name yet. We will loop and keep 'looking for one. End While 'We will never hit this point in execution End Sub '------------------------------------------------------------ 'Attempt to send an i/o stream (e.g. a file) over IR '(ret): ' true: We sent the file successfully ' false: The file was not sent successfully '------------------------------------------------------------ Private Function sendStream(ByRef errorDescription As String, _ ByRef streamOutToIrDA As System.IO.Stream, _ ByRef irDASender As System.Net.Sockets.IrDAClient, _ ByRef streamInFromFile As System.IO.Stream) As Boolean errorDescription = " '---------------------------------------------------------- 'Create a new IRDA client '---------------------------------------------------------- Try '-------------------------------------------------------- 'This will return pretty quickly. It will peek out there 'and will return if no one is listening. '-------------------------------------------------------- irDASender = _ New System.Net.Sockets.IrDAClient(m_IrDAServiceName) Catch eCreateClient As System.Exception 'A number of things could have happened here '1: No devices may be listening '2: A device may be listening, but may not care ' (may refuse our conversation) errorDescription = eCreateClient.Message Return False End Try 'At this point a number of things could happen: '1: We have gotten a connection from an IR receiving device '2: The IR request has been canceled (someone called STOP). If (m_wasSenderStopped = True) Then irDASender.Close() irDASender = Nothing Return False End If '========================================== 'SEND THE DATA! '========================================== 'Open the file we want to send streamInFromFile = System.IO.File.OpenRead(m_fileToSend) 'Open the IrDA socket we want to sent out to streamOutToIrDA = irDASender.GetStream() Const BUFFER_SIZE As Integer = 1024 Dim inBuffer() As Byte ReDim inBuffer(BUFFER_SIZE) Dim bytesRead As Integer Dim iTestAll As Integer Dim iTestWrite As Integer 'Loop... Do 'Read the bytes in from the file bytesRead = streamInFromFile.Read(inBuffer, 0, BUFFER_SIZE) iTestAll = iTestAll + 1 'Write the bytes out to our output stream If (bytesRead > 0) Then streamOutToIrDA.Write(inBuffer, 0, bytesRead) iTestWrite = iTestWrite + 1 End If Loop While (bytesRead > 0) 'Clean up output stream streamOutToIrDA.Flush() 'Finish writing any output streamOutToIrDA.Close() 'Close the stream streamOutToIrDA = Nothing 'Clean up local file streamInFromFile.Close() streamOutToIrDA = Nothing 'Clean up IrDA port irDASender.Close() irDASender = Nothing 'Success!!! Return True End Function End class
Listing 15.5. IrDAFileReceive Class
'--------------------------------------------------------- 'Allows the reception of a file over IrDA (InfraRed port) ' 'This class is NOT re-entrant and should not be called by more 'than one caller at a time. If multiple simultaneous IR 'sessions are desired, they should be done by creating 'different instances of this class. '--------------------------------------------------------- Public Class IrDAFileReceive Private m_wasListenerStopped As Boolean Private m_IrDAServiceName As String Private m_fileNameForDownload As String Private m_errorDuringTransfer As String Private m_irListener As System.Net.Sockets.IrDAListener Private m_ReceiveStatus As ReceiveStatus Public ReadOnly Property ErrorText() As String Get Return m_errorDuringTransfer End Get End Property '-------------------------------------------------------------- 'This notes the status of the receive '-------------------------------------------------------------- Public Enum ReceiveStatus NotDone_SettingUp NotDone_WaitingForSender NotDone_Receiving Done_Success Done_Aborted Done_ErrorOccured End Enum '--------------------------------------------------------- ' Returns the state of transfer '--------------------------------------------------------- Public ReadOnly Property Status() As ReceiveStatus Get SyncLock (Me) Return m_ReceiveStatus End SyncLock End Get End Property Private Sub setStatus(ByVal newStatus As ReceiveStatus) 'Thread safty to aSub read and write at same time SyncLock (Me) m_ReceiveStatus = newStatus End SyncLock 'end lock End Sub '------------------------------------------------------------- ' (in) filename: Filename we want to the IR file into '------------------------------------------------------------- Public Sub New(ByVal filename As String, _ ByVal irdaServiceName As String) 'The name of the IrDA socket we want to open m_IrDAServiceName = irdaServiceName 'The filename we want to save the received data to m_fileNameForDownload = filename End Sub '----------------------------------------------------------- 'Allows you to receive a file asynchronously over IR ' ' (in) filename: Filename to write to '----------------------------------------------------------- Public Sub WaitForIRFileDownloadAsync() 'Note that we are now in setup mode setStatus(ReceiveStatus.NotDone_SettingUp) '----------------------------------------------------------- 'Create a new thread '----------------------------------------------------------- Dim threadEntryPoint As System.Threading.ThreadStart threadEntryPoint = _ New System.Threading.ThreadStart(AddressOf _ WaitForIRFileDownload) Dim newThread As System.Threading.Thread = _ New System.Threading.Thread(threadEntryPoint) 'Start the thread running newThread.Start() End Sub '----------------------------------------------------------- 'Opens up an IR port and waits to download a file '----------------------------------------------------------- Public Sub WaitForIRFileDownload() Dim outputStream As System.IO.Stream Dim irdaClient As System.Net.Sockets.IrDAClient Dim irStreamIn As System.IO.Stream Try '========================================================= 'Set up and download the file! '========================================================= internal_WaitForIRFileDownload(outputStream, irdaClient, _ irStreamIn) Catch 'Swallow any errors that occurred setStatus(ReceiveStatus.Done_ErrorOccured) End Try '============================================= 'Clean up all resources '============================================= 'Close our input stream If Not (irStreamIn Is Nothing) Then Try irStreamIn.Close() Catch 'Swallow any errors that occured End Try End If 'Close the IrDA client If Not (irdaClient Is Nothing) Then Try irdaClient.Close() Catch 'Swallow any errors that occured End Try End If 'Close the file we have been writing to If Not (outputStream Is Nothing) Then Try outputStream.Close() Catch 'Swallow any errors that occured End Try End If 'Close the listener if its running If Not (m_irListener Is Nothing) Then 'Set first so code running on another thread will 'abort if it is set m_wasListenerStopped = True Try m_irListener.Stop() Catch 'Swallow any errors End Try m_irListener = Nothing End If End Sub Private Sub internal_WaitForIRFileDownload( _ ByRef outputStream As System.IO.Stream, _ ByRef irdaClient As System.Net.Sockets.IrDAClient, _ ByRef irStreamIn As System.IO.Stream) '---------------------------------------------------------- 'Open an input file to stream into '---------------------------------------------------------- outputStream = System.IO.File.Open( _ m_fileNameForDownload, _ System.IO.FileMode.Create) '========================================== 'STATUS UPDATE '========================================== setStatus(ReceiveStatus.NotDone_WaitingForSender) '------------------------------------------------------------- 'Open a listener '------------------------------------------------------------- Try m_wasListenerStopped = False m_irListener = _ New System.Net.Sockets.IrDAListener(m_IrDAServiceName) m_irListener.Start() Catch eListener As System.Exception m_errorDuringTransfer = "Error creating listener - " + _ eListener.Message GoTo exit_sub_with_error End Try 'See if we got aborted If (m_wasListenerStopped = True) Then GoTo exit_sub_with_abort End If '--------------------------------------------------------- 'Accept a connection '--------------------------------------------------------- Try '--------------------------------------------------------- 'Execution will stop here until we get pinged by a device 'or the listener was halted on another thread '--------------------------------------------------------- irdaClient = m_irListener.AcceptIrDAClient() Catch eClientAccept As System.Exception 'If the listenting is stopped by another thread calling cancel ' an exception will be thrown and we will be here. If (m_wasListenerStopped = True) Then GoTo exit_sub_with_abort End If 'If it was not a matter of the listening service being 'stopped, some other exception has occurred. Deal with it. m_errorDuringTransfer = "Error accepting connection - " + _ eClientAccept.Message GoTo exit_sub_with_error End Try 'At this point we will be in 1 of 2 states, either: '1: We have gotten a connection from an IR sending device '2: The IR request has been canceled (by someone calling STOP) ' (in which the code below will throw an exception) 'See if we got aborted If (m_wasListenerStopped = True) Then GoTo exit_sub_with_abort End If '========================================== 'STATUS UPDATE '========================================== setStatus(ReceiveStatus.NotDone_Receiving) '-------------------------------------------------------------- 'Open a receiving stream '-------------------------------------------------------------- Try irStreamIn = irdaClient.GetStream() Catch exGetInputStream As System.Exception m_errorDuringTransfer = "Error getting input stream - " + _ exGetInputStream.Message GoTo exit_sub_with_error End Try 'Get ready to receive the data! Const BUFFER_SIZE As Integer = 1024 Dim inBuffer() As Byte ReDim inBuffer(BUFFER_SIZE) Dim bytesRead As Integer Do 'Read the bytes in from the IR port bytesRead = irStreamIn.Read(inBuffer, 0, BUFFER_SIZE) 'Write the bytes out to our output stream If (bytesRead > 0) Then outputStream.Write(inBuffer, 0, bytesRead) End If Loop While (bytesRead > 0) outputStream.Flush() 'Finish writing any output '========================================== 'STATUS UPDATE: SUCCESS '========================================== setStatus(ReceiveStatus.Done_Success) Return 'No errors '========================================== 'FAILURE. '========================================== exit_sub_with_abort: 'STATUS UPDATE: Aborted (but no error) setStatus(ReceiveStatus.Done_Aborted) Return exit_sub_with_error: 'STATUS UPDATE: ERROR!!!! setStatus(ReceiveStatus.Done_ErrorOccured) End Sub End Class
Listing 15.6. Simple Web Wervice
'This code snippet goes inside the Service1 class 'in the file "Service1.asmx.vb". ' '"<WebMethod>" is meta data that tells the Web service 'engine that this method should be exposed as a Web service <WebMethod()> _ Public Function AddTwoNumbers(ByVal x As Integer, _ ByVal y As Integer) As Integer Return x + y End Function
Listing 15.7. Web Service Calls with Only Explicit Parameters Being Passed This is just a series of function calls. It should be easy for VB programmers to follow the C# code.Listing 15.8. Web Service Calls with Implicit Parameters Passed via Cookies This is just a series of function calls. It should be easy for VB programmers to follow the C# code.Listing 15.9. A Chatty Conversation with a Multiple Web Service Calls This is just a series of function calls. It should be easy for VB programmers to follow the C# code.Listing 15.10. A Batched Conversation with a Single Web Service Call This is just a series of function calls. It should be easy for VB programmers to follow the C# code.Listing 15.11. Code to Download a File from a Web Server
'------------------------------------------------------------- 'Performs a synchronous download of a file on a Web server 'of a file and stores it to a local file system ' (in) httpWhereFrom: URL to file ' (e.g. "http:'someserver/somefile.jpg") ' (in) filenameWhereTo: File location to write the file to ' (e.g. "\localfile.jpg") '------------------------------------------------------------- Public Sub downloadFileToLocalStore(ByVal httpWhereFrom As _ String, ByVal filenameWhereTo As String) Dim myFileStream As System.IO.FileStream = Nothing Dim myHTTPResponseStream As System.IO.Stream = Nothing Dim myWebRequest As System.Net.WebRequest = Nothing Dim myWebResponse As System.Net.WebResponse = Nothing 'If the location we want to write to exists, delete it If (System.IO.File.Exists(filenameWhereTo) = True) Then System.IO.File.Delete(filenameWhereTo) End If Try 'Create a Web request myWebRequest = _ System.Net.HttpWebRequest.Create(httpWhereFrom) 'Get the response myWebResponse = myWebRequest.GetResponse() 'Get the stream for the response myHTTPResponseStream = myWebResponse.GetResponseStream() 'Create a local file to stream the response to myFileStream = System.IO.File.OpenWrite(filenameWhereTo) 'This buffer size can be tuned Const buffer_length As Integer = 4000 Dim byteBuffer() As Byte ReDim byteBuffer(buffer_length) Dim bytesIn As Integer 'Read in the file and stream it to a local file Do 'Read data in bytesIn = myHTTPResponseStream.Read(byteBuffer, _ 0, buffer_length) 'Write data out If (bytesIn <> 0) Then myFileStream.Write(byteBuffer, 0, bytesIn) End If Loop While (bytesIn <> 0) Catch myException As Exception 'Download failed! 'Something bad happened. Let's clean up attemptCleanup_ThrowNoExceptions(myFileStream, _ myHTTPResponseStream, myWebResponse) 'Now that we've cleaned up, rethrow the exception 'so that the application knows something went wrong! Throw myException End Try 'Download has succeeded! 'Let's close everyting down. Try 'Normal clean up. myFileStream.Close() myFileStream = Nothing myHTTPResponseStream.Close() myHTTPResponseStream = Nothing myWebResponse.Close() myWebResponse = Nothing Catch myException As Exception 'Failure during a close! 'Something bad happened. Let's clean up attemptCleanup_ThrowNoExceptions(myFileStream, _ myHTTPResponseStream, myWebResponse) 'Now that we've cleaned up, rethrow the exception 'so that the the application knows something went wrong! Throw myException End Try 'Success! End Sub '------------------------------------------ 'Tries to close and clean up everything 'Traps any exceptions that might be thrown. '------------------------------------------ Sub attemptCleanup_ThrowNoExceptions( _ ByVal myFileStream As System.IO.FileStream, _ ByVal myHTTPResponseStream As System.IO.Stream, _ ByVal myWebResponse As System.Net.WebResponse) If Not (myFileStream Is Nothing) Then Try myFileStream.Close() Catch 'Do nothing. End Try End If If Not (myHTTPResponseStream Is Nothing) Then Try myHTTPResponseStream.Close() Catch 'Do nothing. End Try End If If Not (myWebResponse Is Nothing) Then Try myWebResponse.Close() Catch 'Do nothing. End Try End If End Sub
|