我正在就我的测试的有效性寻求一些第二意见。
简而言之,我使用 MMF 来模拟从 WinForms 客户端到 Windows 服务的同步方法调用。由于此处讨论的原因,WCF 和命名管道都不适用于此。
对于我的原型,我创建了两个简单的应用程序——一个控制台应用程序代表 WinForms“客户端”,一个 WinForms 应用程序代表 WinService“服务器”。
我必须克服两个主要问题:1)服务器的计时器每三秒触发一次,2)操作系统似乎需要至少一整秒来获取然后释放互斥锁。这第二点让我很好奇。我原以为这个过程是即时的,但显然我错了。
为了解决这两个问题,我使用了 Thread.Sleep——两秒钟等待服务器的计时器,一秒钟等待互斥体处理。任何小于这些的间隔都会导致间歇性读/写同步失败。当然,您可以随意调整代码以获得您自己的结果。
我的测试由客户端中的 30,000 次迭代循环组成,该循环“调用”服务器中的“方法”并将响应写入日志文件。目前我在迭代 ~22,500 没有任何错误。
我的问题:有人看到我的测试有任何问题吗?鉴于我的 MSDN 帖子(上面链接)中指出的要求,到目前为止我的结果是否表明设计稳定?
也就是说,如果我的架构可以改进,我会非常有兴趣听到它。
这是代码:
控制台(客户端)
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading
Imports System.Text
Imports System.Security.Cryptography
Module Main
Sub Main()
Dim _
sForward,
sReverse,
sOutput As String
Console.WriteLine("Enter a string to reverse:")
For iCount As Integer = 0 To 29999
sForward = GetRandomString(7)
sReverse = ReverseString(sForward)
sOutput = sForward & " => " & sReverse
File.AppendAllText("Output.log", sOutput & vbCrLf)
Console.WriteLine(sOutput)
Thread.Sleep(1000)
Next
Console.ReadLine()
End Sub
Private Function GetRandomString(Length As Integer) As String
Dim sSeedText As String
Dim oBuilder As StringBuilder
Dim aBuffer As Byte()
Dim oCrypto As RNGCryptoServiceProvider
sSeedText = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
oBuilder = New StringBuilder
aBuffer = New Byte(Length - 1) {}
oCrypto = New RNGCryptoServiceProvider
oCrypto.GetNonZeroBytes(aBuffer)
For Each bByte As Byte In aBuffer
oBuilder.Append(sSeedText.Chars(bByte Mod sSeedText.Length))
Next
Return oBuilder.ToString
End Function
Private Function ReverseString(Data As String) As String
Dim lIsOwner As Boolean
Dim iLength As Integer
Dim aData As Byte()
aData = Encoding.Unicode.GetBytes(Data)
iLength = aData.Length
Using oFile As MemoryMappedFile = MemoryMappedFile.CreateNew("{99EC7026-0059-4D48-99B1-B400BDACBDD8}", 1024)
Using oMutex As New Mutex(True, "{35C4F5C6-874B-4536-901A-D5382B7E2B9C}", lIsOwner)
'*=====================================================================
' Wait for the server's Timer.Tick event to fire
'*=====================================================================
Thread.Sleep(2000)
'*=====================================================================
Using oStream As MemoryMappedViewStream = oFile.CreateViewStream(0, 0)
Using oWriter As New BinaryWriter(oStream)
oWriter.Write(iLength)
oWriter.Write(aData)
End Using
End Using
oMutex.ReleaseMutex()
'*=====================================================================
' Wait for the server to acquire and then release the mutex
'*=====================================================================
Thread.Sleep(1000)
'*=====================================================================
oMutex.WaitOne()
Using oStream As MemoryMappedViewStream = oFile.CreateViewStream(iLength + 4, 0)
Using oReader As New BinaryReader(oStream)
With oReader
aData = .ReadBytes(.ReadInt32)
End With
End Using
End Using
oMutex.ReleaseMutex()
End Using
End Using
Return Encoding.Unicode.GetString(aData)
End Function
End Module
WinForms(服务器)
'*=============================================================================
'
' Add a ListBox
' Add a Background Worker
' Add a Windows Forms Timer
' Interval = 3000
' Enabled = True
'
'*=============================================================================
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.ComponentModel
Imports System.Threading
Imports System.Text
Public Class Main
Private Sub tmrTimer_Tick(Sender As Object, e As EventArgs) Handles tmrTimer.Tick
Dim lIsOpen As Boolean
Dim oFile As MemoryMappedFile
tmrTimer.Stop()
Try
lIsOpen = True
oFile = MemoryMappedFile.OpenExisting("{99EC7026-0059-4D48-99B1-B400BDACBDD8}")
bgwWorker.RunWorkerAsync(oFile)
Catch ex As FileNotFoundException
lIsOpen = False
End Try
If Not lIsOpen Then
tmrTimer.Start()
End If
End Sub
Private Sub bgwWorker_DoWork(Sender As Object, e As DoWorkEventArgs) Handles bgwWorker.DoWork
Dim iLength As Integer
Dim sData As String
Dim aData As Byte()
Using oFile As MemoryMappedFile = e.Argument
Using oMutex As Mutex = Mutex.OpenExisting("{35C4F5C6-874B-4536-901A-D5382B7E2B9C}")
oMutex.WaitOne()
Using oStream As MemoryMappedViewStream = oFile.CreateViewStream(0, 0)
Using oReader As New BinaryReader(oStream)
With oReader
aData = .ReadBytes(.ReadInt32)
End With
End Using
End Using
sData = Encoding.Unicode.GetString(aData)
aData = Encoding.Unicode.GetBytes(New String(sData.Reverse.ToArray))
iLength = aData.Length
Using oStream As MemoryMappedViewStream = oFile.CreateViewStream(iLength + 4, 0)
Using oWriter As New BinaryWriter(oStream)
oWriter.Write(iLength)
oWriter.Write(aData)
End Using
End Using
oMutex.ReleaseMutex()
End Using
End Using
e.Result = sData
End Sub
Private Sub bgwWorker_RunWorkerCompleted(Sender As Object, e As RunWorkerCompletedEventArgs) Handles bgwWorker.RunWorkerCompleted
lstArguments.Items.Add(e.Result)
tmrTimer.Start()
End Sub
End Class