All pastes #479343 Raw Edit

fuzzy

public text v1 · immutable
·published 2007-05-09 17:58 UTC
rendered paste body
Imports System
Imports System.Collections
Imports System.Text
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Threading
'Imports System.Windows.Forms

Namespace UsingSockets
End Namespace 'UsingSockets
Class Window1

    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        ' Create the delegate using the method to update the UI
        _invokeControl = New InvokeControl(AddressOf InvokeUIThread)
        CreateURLList()
        SpinUpSocketPool(socketPool)
        Dim threads(NUMBER_WORKER_THREADS) As Thread
        Dim count As Integer
        For count = 1 To threads.Length - 1
            threads(count) = New Thread(New ThreadStart(AddressOf Search))
            threads(count).Start()
        Next count
    End Sub

    ' The .NET 2.0 socket enhancements include an asynchronous Connect method and a Disconnect method
    ' to allow a socket to be re-used without the overhead of creating a new socket.  The following example uses these
    ' new features to create a socket pool to allow worker threads to rapidly search URL's and retrieve
    ' their home page content.  The new features go hand-in-hand as a disconnected socket can only
    ' be re-used by issuing an asynchronous connect.

    ' Total number of sockets in the pool
    Private Shared SOCKET_POOL_SIZE As Integer = 10

    ' Total number of worker threads
    Private Shared NUMBER_WORKER_THREADS As Integer = 3

    ' Flag to continue thread run
    Public Shared runThreads As Boolean = True

    ' Index into URL list, incremented be each thread
    Private Shared currentURLCounter As Integer = 0

    Private Shared socketPool As New ArrayList(SOCKET_POOL_SIZE)
    Private Shared urlList As New ArrayList()

    ' Delegate to allow cross-thread update of UI safely
    Delegate Sub InvokeControl(ByVal [text] As String)
    Private Shared _invokeControl As InvokeControl

    ' Spins up a number of sockets to send data via TCP
    ' socketPool is the ArrayList to be populated with Socket objects
    Private Sub SpinUpSocketPool(ByVal socketPool As ArrayList)
        Dim i As Integer
        For i = 0 To SOCKET_POOL_SIZE - 1
            socketPool.Add(New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
        Next i
    End Sub 'SpinUpSocketPool
    ' Create a list of URL's by appending a counter to the searchURL
    ' pointing at a handy list of known sequential URL's
    Private Sub CreateURLList()
        urlList.Add("SERVO1")
    End Sub 'CreateURLList

    ' Thread event notifier for asynchronous connects
    Public Shared allDone As New ManualResetEvent(False)

    ' .NET 2.0 callback that handles the completion of the prior asynchronous 
    ' connect call. The socket is passed contained in the IAsyncResult param via 
    ' the last paramater of Socket.BeginConnect().
    ' ar is the state-containing object
    Public Sub ConnectCallback(ByVal ar As IAsyncResult)
        allDone.Set()
        Dim s As Socket = CType(ar.AsyncState, Socket)
        Try
            s.EndConnect(ar)
        Catch
        End Try
    End Sub 'ConnectCallback

    ' Lock the socket pool and find a non-connected socket, then connect it.
    ' server is The address to connect the socket to
    ' returns the connected socket
    Private Function ConnectSocket(ByVal server As String) As Socket
        Dim s As Socket = Nothing
        ' Get host related information.
        UpdateText("Trying " + server)
        While runThreads
            SyncLock socketPool
                Dim i As Integer
                For i = 0 To SOCKET_POOL_SIZE - 1
                    s = CType(socketPool(i), Socket)
                    If Not s.Connected Then
                        allDone.Reset()
                        Try
                            s.BeginConnect(server, 10001, New AsyncCallback(AddressOf ConnectCallback), s)
                        Catch
                        End Try
                        ' possible unknown host
                        ' wait here until the connect finishes.  The callback 
                        ' sets allDone.
                        allDone.WaitOne()
                        Return s
                    End If
                Next i
                UpdateText("Out of Sockets!, waiting...")
                Monitor.Wait(socketPool)
                UpdateText("Socket added to pool, trying recycled socket")
            End SyncLock
        End While
        Return Nothing
    End Function 'ConnectSocket

    '/ Request the home page content for the specified server.
    '/ server is the address from which to retrieve data
    Private Sub SocketSendReceive(ByVal server As String)
        'Dim request As String = "GET / HTTP/1.1" + ControlChars.Cr + ControlChars.Lf + "Host: " + server + ControlChars.Cr + ControlChars.Lf + "Connection: Close" + ControlChars.Cr + ControlChars.Lf + ControlChars.Cr + ControlChars.Lf
        Dim request As String = "99ID" & Chr(13)
        Dim bytesSent As [Byte]() = Encoding.ASCII.GetBytes(request)
        Dim bytesReceived(10) As [Byte]

        ' Create a socket connection asynchronously with the specified server and port.
        Dim s As Socket = ConnectSocket(server)

        If s Is Nothing Or Not s.Connected Then
            UpdateText("Failed to connect socket to " + server)
            Return
        End If
        UpdateText("Socket Connected to " + server)
        ' Send request to the server.
        s.Send(bytesSent, bytesSent.Length, 0)

        ' Receive the server home page content.
        Dim bytes As Integer = 0
        Dim page As String = ""

        ' The following will block until the page contents are retrieved
        Do
            bytes = s.Receive(bytesReceived, bytesReceived.Length, 0)
            page = page + Encoding.ASCII.GetString(bytesReceived, 0, bytes)
        Loop While bytes > 0

        ' Use the .NET 2.0 Disconnect method to place the socket back in circulation
        s.Shutdown(SocketShutdown.Both)
        s.Disconnect(True) ' boolean true as argument allows socket reuse
        ' Notify any waiter on the socket pool that a socket has become available
        SyncLock socketPool
            Monitor.Pulse(socketPool)
        End SyncLock

        UpdateText("Retrieved " + page.Length.ToString() + " bytes from " + server)
    End Sub 'SocketSendReceive


    '/ Per-thread method to take next URL from list, incrementing the index into
    '/ the URL list.
    Public Sub Search()
        Dim url As String = Nothing
        While runThreads
            SyncLock urlList
                If currentURLCounter = urlList.Count Then
                    Return
                End If
                url = CType(urlList(currentURLCounter), [String])
                currentURLCounter = currentURLCounter + 1
            End SyncLock
            SocketSendReceive(url)
        End While
    End Sub 'Search

    ' In order to safely update the UI across threads, a delegate with this method is
    ' called using Control.Invoke
    Private Shared Sub InvokeUIThread(ByVal [text] As String)
        Dim listbox1 As New ListBox
        listbox1.Items.Add([text])
    End Sub 'InvokeUIThread

    Private Sub UpdateText(ByVal [text] As String)
        Try
            'ListBox1.invoke(_invokeControl, [text])
            _invokeControl([text])

        Catch
        End Try
    End Sub 'UpdateText
    Private Sub Window1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles Me.Closing
        runThreads = False
    End Sub

End Class 'Program