程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> Visual Basic語言 >> VB.NET >> 在vb.net中運用多線程完成近程數據搜集

在vb.net中運用多線程完成近程數據搜集

編輯:VB.NET

在vb.net中運用多線程完成近程數據搜集。本站提示廣大學習愛好者:(在vb.net中運用多線程完成近程數據搜集)文章只能為提供參考,不一定能成為您想要的結果。以下是在vb.net中運用多線程完成近程數據搜集正文


引言

在筆者參與的四川省重點淨化源企業環境近程監控零碎中,有一項十分重要的任務:將多達80台的近程DVS(視頻服務器)的監測數據經過因特網傳輸,由上位機搜集下去,寫入SQL Server 2005數據庫中。近程數據每隔一分鐘發送一次實時數據。假如數據在一分鐘內傳送不成功,那麼DVS將以為網絡曾經斷開,又要不時的發起新的銜接。因而,上位機能不能及時的精確的搜集、寫入,是零碎成敗的關鍵。

項目剖析

80多台近程DVS正在不連續的采集數據,在網絡正常的狀況下,會不連續的向上位機發送數據。假如采用傳統的單線程構造,上位機承受銜接懇求,接納處置數據,將數據寫入數據庫,然後再承受新的銜接懇求,接納處置數據,……,這樣,上位機順序異常忙碌,CPU應用率簡直將達100%。由於服務器不能迅速處置懇求,DVS只好等候。

更為重要的是,為了增加上位機發送呼應銜接的次數,設備采用的是長銜接,即發送一次銜接懇求並失掉呼應後,發送數據時不再發送銜接懇求。因而,要求上位機可以保管客戶端的Socket。

為了防止這種情形發作。筆者采用了異步、多線程來處置。所謂異步,是順序調用一個辦法後立刻前往,總體而言,主線程與辦法線程並行執行。而同步即順序執行一個辦法,等該辦法前往之後,持續往下走,本零碎從功用上分紅3個模塊,即3個前後關聯的線程:主線程、數據接納線程、存入數據庫線程,它們異步執行。

主線程

主線程任務流程如圖一所示。其次要功用是:初始化參數,如銜接端口號、IP地址等,偵聽銜接懇求,將傳入的銜接保存到TcpClient對象數組sockets,而這個數組sockets恰恰是我們前面線程中要用到的全局變量。 為了不使線程間爭用這個數組變量,這裡用到了VB.net提供的Monitor類,它提供同步對象的訪問的機制。

當主線程偵聽到近程DVS有銜接懇求時,立刻執行AcceptTcpClient辦法,創立一個TcpClient實例,並將它放入sockets數組。同時創立線程對象serverthread。

聲明創立線程時,運用 ThreadStart 委托作為其獨一參數的結構函數創立 Thread 類的新實例,創立線程時需求傳遞處置銜接的進程或函數的地址以被線程調用。創立線程委托,傳遞需求操作的進程的地址,這局部的代碼如下所示:

Public Sub WaitData()

Try

Dim ipHostInfo As IPHostEntry = Dns.Resolve(Dns.GetHostName())

Dim localAddr As IPAddress = ipHostInfo.AddressList(0)

s = New TcpListener(localAddr, ListenPort)

s.Start()’開端偵聽銜接懇求

Dim Recdatathread As New Thread(New ThreadStart(AddressOf RecDataProc)) ’創立數據接納線程

Recdatathread.IsBackground = True

Recdatathread.Start()’啟動線程

While True

Dim client As TcpClient = s.AcceptTcpClient()

Monitor.Enter(sockets) '在指定對象上獲取排他鎖

sockets(socketcount) = client

socketcount = socketcount + 1

Monitor.Exit(sockets) '釋放指定對象上的排他鎖

End While

Catch e As SocketException

s.Stop()

saveErrLog(Date.Now, CType(s.AcceptTcpClient.Client.RemoteEndPoint, IPEndPoint).Address.ToString(), e.Message)’寫入錯誤日志

Catch e As ThreadAbortException

t.Abort()

saveErrLog(Date.Now, CType(s.AcceptTcpClient.Client.RemoteEndPoint, IPEndPoint).Address.ToString(), e.Message) ’寫入錯誤日志

Finally

t.Abort()

End

End Try

End Sub

數據接納線程

數據接納線程的任務流程如圖二所示。次要功用是:將掛起銜接的DVS上傳數據從流中讀取出來,創立數據寫入線程,並在listbox中顯示。

從保管的socket數組中讀取字節流時,必需思索以下問題:

一、有些DVS能夠會在任務一段時間後發作設備毛病或許網絡中綴,但服務器保管的是其歷史socket,因而,必需判別其connect屬性,即設備能否在線。

二、為了增加服務器的空等時間,必需判別流對象(stream)的DataAvailable屬性。

三、創立線程saveToDb時,必需思索傳入參數的問題。通常的線程創立是不可提供參數的。我們將線程saveToDb的執行體封裝到一個類中,經過初始化類的成員變量的辦法,來到達傳送參數的目的。

四、由於本線程是長駐內存並循環執行的。因而,該當在適當的中央阻止,否則,CPU的應用率將達簡直100%。

這局部的代碼如下:

Public Sub RecDataProc()

Dim i As Integer

Dim c As TcpClient

While (True)

Try

For i = 0 To socketList.Count - 1

If socketList.Item(i).client.connected Then '假如該銜接在線

Dim dh1 As DelegateHandler = New DelegateHandler(AddressOf displayStatusBarPanel2)

'New 出一個委托並指定委托辦法

Me.Invoke(dh1, New Object() {CStr(i)})  '調用invoke辦法

c = socketList.Item(i)

Dim stream As NetworkStream = c.GetStream()

If stream.DataAvailable Then

Dim dh As DelegateHandler1 = New DelegateHandler1(AddressOf ShowInBox)

Dim readbuff As New ReadBuffClass(c, stream, Connection, dh) '由結構函數來初始化成員變量

ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf readbuff.ReadBuff), readbuff)’把詳細從流中讀取數據的任務交給線程池的線程來停止

Dim workerThreads, portThreads As Integer

ThreadPool.GetAvailableThreads(workerThreads, portThreads)

Dim dh2 As DelegateHandler = New DelegateHandler(AddressOf displayStatusBarPanel4)

'New 出一個委托並指定委托辦法

Me.Invoke(dh2, New Object() {workerThreads.ToString})  '調用invoke辦法

End If

Thread.Sleep(20) '假如不阻止,則CPU應用率將為100%

End If

Next

Catch ex As System.ArgumentOutOfRangeException

Catch ex As System.InvalidOperationException

Catch ex As ObjectDisposedException 'TcpClient 已封閉

Catch ex As SocketException

Catch ex As ThreadAbortException

Catch ex As System.IO.IOException

Catch ex As System.AccessViolationException

Finally

End Try

End While

End Sub

數據處置線程

這部份線程每個都由線程池來調度運轉。由於要接納線程參數,因而,線程自身被封裝到一個類中,限於篇幅的緣由,只描繪類的構造。

Public Class ReadBuffClass

Private sck As TcpClient

Private ns As NetworkStream

Private sqlcnn As SqlConnection

Private delg As frmServerMain.DelegateHandler1

Dim sqlcmd As SqlCommand

Dim sqlda As SqlDataAdapter

Public Sub New(ByVal sc As TcpClient, ByVal n As NetworkStream, ByVal cn As SqlConnection, ByVal dh As frmServerMain.DelegateHandler1) '由結構函數來初始化成員變量

Me.sck = sc

Me.ns = n

Me.sqlcnn = cn

Me.delg = dh

End Sub

Public Sub ReadBuff(ByVal state As Object) ' 線程的入口函數

Dim datastring As String = ""

ns.ReadTimeout = 100 '讀取失敗前閱歷的毫秒數

Try

While (True)

Dim bytes(2048) As Byte

ns.Read(bytes, 0, 2048)

datastring = datastring + Encoding.ASCII.GetString(bytes)

If datastring.IndexOf(vbCrLf) > 0 Then

Exit While

End If

End While

delg.Invoke(datastring, sck) '經過委托的方式,將參數傳給UI

Dim tmparr() As String = datastring.Split("##")

Dim i As Integer

For i = 0 To tmparr.Length - 1

If tmparr(i) <> "" Then

ProcessInfo(tmparr(i))

End If

Next

Catch ex As System.AccessViolationException

Catch ex As NotSupportedException

Catch ex As ArgumentNullException

Catch ex As ArgumentOutOfRangeException

Catch ex As ObjectDisposedException

Catch ex As IO.IOException '

Catch ex As SocketException

Catch ex As ThreadAbortException

Finally

End Try

End Sub

Private Sub ProcessInfo(ByVal tmpString As String) '對收到的數據停止解析、處置

……

End Sub

……

End Class

完畢語

本文著重闡述的是在VB2005的環境下,運用多線程異步完成近程DVS數據搜集的原理,重點思索的是怎樣進步順序的反響速度,特別討論了順序開發中的一些細節問題,對有志於從事近程臨控零碎開發的軟件人員有一定的參考意義。

文中代碼在windows2003+VB2005+SqlServer2005的環境下調試經過,如今正在運用。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved