客户端 - 服务器文件传输出错

时间:2014-07-14 13:26:12

标签: vb.net multithreading sockets

由于某种原因,我开发的这段代码在使用无线网络时随机失败(我似乎无法在局域网上重现问题)。似乎是在即将传输新文件时,服务器不会发送任何字节。

客户端

Option Explicit Off
Imports System.Net.Sockets
Imports System.Net
Imports System.Threading
Imports System.IO
Imports NetFwTypeLib


Public Class UpdateReleaseForm

Public IP As String
Dim CheckNetworkThread As Thread
Dim SendItClient As TcpClient
Dim netStream As NetworkStream
Dim NumberOfBytes As ULong
Dim SumOfAllBytes As ULong = 0
Dim TotalNumberOfBytes As ULong
Dim NumberOfBytesInThisSecond As Integer = 0
Dim AllNew As Boolean
Dim DownloadFile As Boolean
Public UpgradeTo As String
Declare Sub Sleep Lib "Kernel32.dll" (ByVal ms As Short)
Dim netStreamn As NetworkStream
Dim writer As BinaryWriter
Dim SendItClientn As TcpClient


Private Sub Button1_Click(sender As Object, e As EventArgs) Handles YesButton.Click

    If YesButton.Text = "Yes" Or YesButton.Text = "Resume" Then
        DownloadFile = True
        Try
            SendItClient = New TcpClient
            SendItClient.Connect(IP, 8001)
            netStream = SendItClient.GetStream
        Catch ex As System.Net.Sockets.SocketException
            MessageBox.Show("Could not establish a connection with server. Please try again later.", "Notification", MessageBoxButtons.OK)
            Exit Sub
        End Try

        If Directory.Exists("C:\Results\") = False Then
            Directory.CreateDirectory("C:\Results\")
        End If

        If Directory.Exists("C:\Results\Updates") = False Then
            Directory.CreateDirectory("C:\Results\Updates\")
        End If

        If Directory.Exists("C:\Results\Updates\" & UpgradeTo) = False Then
            Directory.CreateDirectory("C:\Results\Updates\" & UpgradeTo)
            AllNew = True
        Else
            AllNew = False
        End If


        Dim ProcessIt As New Thread(AddressOf Process)
        ProcessIt.IsBackground = True
        ProcessIt.Start()

        Dim BytesPerSecondThread As New Thread(AddressOf BytesPerSecond)
        BytesPerSecondThread.IsBackground = True
        BytesPerSecondThread.Start()
        NoButton.Enabled = False
        YesButton.Enabled = False
    Else
        DownloadFile = False
        writer.Close()
        netStreamn.Close()
        SendItClientn.Close()
        YesButton.Text = "Resume"
        NoButton.Enabled = True
    End If

End Sub

Private Sub Process()
    Dim valid As Boolean = True
    Dim number As Integer 'number of packet
    Dim FilePath As String
    Dim portN As ULong
    Dim buff2(0) As Byte
    Dim TimeItThread As New Thread(AddressOf TimeIt)

    While valid = True
        Dim buffer(65000 - 1) As Byte
        Dim bytesRead As Integer = netStream.Read(buffer, 0, buffer.Length)

        number = BitConverter.ToInt64(buffer, 0)

        NumberOfBytes = number

        TotalNumberOfBytes = BitConverter.ToUInt64(buffer, 8)
        UpdateProgressBarMax(ProgressBar1, TotalNumberOfBytes)

        portN = BitConverter.ToInt64(buffer, 16)

        FilePath = System.Text.Encoding.ASCII.GetString(buffer, 25, buffer(24)) 'filename


        If My.Computer.FileSystem.FileExists("C:\Results\Updates\" & UpgradeTo & FilePath) = False Then
            Directory.CreateDirectory(Path.GetDirectoryName("C:\Results\Updates\" & UpgradeTo & FilePath))
        End If

        GetFile(FilePath, portN)

        If DownloadFile = False Then
            Exit Sub
        End If


        If TotalNumberOfBytes = SumOfAllBytes Then
            Exit While
        End If

    End While

    ChangeText(Label2, "Download Completed")
    UpdateProgressBarValue(ProgressBar1, SumOfAllBytes)
    'EnableControl(YesButton, True)
    'EnableControl(NoButton, True)

    Dim myProcess As New Process()


    Try
        myProcess.StartInfo.UseShellExecute = False
        myProcess.StartInfo.FileName = "C:\Results\Updates\" & UpgradeTo & "\Setup.exe"
        myProcess.StartInfo.CreateNoWindow = True
        myProcess.Start()
    Catch ex As Exception
        MessageBox.Show("Error updating", "Warning")
        CloseThisForm()
        Exit Sub
    End Try

    Do While True
        If myProcess.HasExited = True Then
            CloseThisForm()
            Exit Sub
        End If
        Sleep(50)
    Loop
End Sub

Private Sub TimeIt()
    Dim initial As DateTime
    Dim PrevBytes As ULong
    Dim bps As ULong


    initial = Now
    PrevBytes = 0

    While TotalNumberOfBytes <> SumOfAllBytes
        If DateDiff(DateInterval.Second, initial, Now) >= 0 Then
            initial = Now
            bps = SumOfAllBytes - PrevBytes
            PrevBytes = SumOfAllBytes
            ChangeText(Label3, bps)
        End If
    End While
End Sub


Private Sub GetFile(ByVal filep As String, ByVal PortNum As Integer)
    ' Dim Buffer(1026 - 1) As Byte
    Dim Buffer(10024 - 1) As Byte
    Dim count As Integer = 0
    Dim buff2(0) As Byte
    Dim bytesReadSum As ULong = 0
    Dim NumberAlready As ULong
    Dim holdit(0) As Byte

    SendItClientn = New TcpClient

    Try
        SendItClientn.Connect(IP, PortNum)
    Catch ex As Exception
        'failure to connect when either server or network drops out
        MessageBox.Show("Something went wrong there", "Warning")
        DownloadFile = False
        Exit Sub
    End Try

    netStreamn = SendItClientn.GetStream


    If File.Exists("C:\Results\Updates\" & UpgradeTo & filep) Then
        Dim fstm As Stream = New FileStream("C:\Results\Updates\" & UpgradeTo & filep, FileMode.Open, FileAccess.Read)
        NumberAlready = fstm.Length()
        fstm.Close()
        writer = New BinaryWriter(System.IO.File.Open("C:\Results\Updates\" & UpgradeTo & filep, FileMode.Append))
    Else
        NumberAlready = 0
        writer = New BinaryWriter(System.IO.File.Open("C:\Results\Updates\" & UpgradeTo & filep, FileMode.Create))
    End If


    Dim NumberAlreadyBytes() As Byte = BitConverter.GetBytes(NumberAlready)
    netStream.Write(NumberAlreadyBytes, 0, NumberAlreadyBytes.Length)
    bytesReadSum = NumberAlready
    SumOfAllBytes += NumberAlready

    If NumberOfBytes = NumberAlready Then
        netStream.Write(buff2, 0, buff2.Length)
        writer.Close()
        Exit Sub
    End If

    Do While True

        If DownloadFile = False Then
            TotalNumberOfBytes = 0
            SumOfAllBytes = 0
            writer.Close()
            SendItClient.Close()
            netStreamn.Close()
            Exit Sub
        End If

        Dim bytesRead As ULong

        'ReDim Buffer(10024 - 1)
        'Dim Buffer(10026 - 1)
        'ReDim Buffer(1026 - 1)
        ReDim Buffer(10024 - 1)


        Try
            bytesRead = netStreamn.Read(Buffer, 0, Buffer.Length)
        Catch ex As Exception
            MessageBox.Show("Something went wrong there. Software will now close.", "Warning")
            End
        End Try



        bytesReadSum += bytesRead
        SumOfAllBytes += bytesRead
        NumberOfBytesInThisSecond = NumberOfBytesInThisSecond + bytesRead
        UpdateProgressBarValue(ProgressBar1, SumOfAllBytes)
        ChangeText(Label2, CInt(SumOfAllBytes / TotalNumberOfBytes * 100) & "% downloaded")

        ReDim Preserve Buffer(bytesRead - 1)

        Try
            writer.Write(Buffer)
        Catch ex As Exception
            MessageBox.Show("Something went wrong there. Software will now close.", "Warning")
            End
            'Exit Sub
        End Try

        If bytesReadSum >= NumberOfBytes Then
            Exit Do
        End If

        If bytesRead = 0 Then
            MessageBox.Show("Something went wrong there. Software will now close.", "Warning")
            End
        End If

        count += 1
    Loop
    netStream.Write(buff2, 0, buff2.Length)
    buff2(0) = 1
    writer.Close()
End Sub

Private Sub UpdateReleaseForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub

Private Sub Closing() Handles Me.FormClosing
    Try
        DownloadFile = False
        netStreamn.Close()
        SendItClient.Close()
    Catch ex As Exception
    End Try
End Sub

Delegate Sub UpdateProgressBarValueDelegate(ByVal progressB As ProgressBar, ByVal value As Integer)

Public Sub UpdateProgressBarValue(ByVal progressB As ProgressBar, ByVal value As Integer)
    'If not on main thread then
    If progressB.InvokeRequired Then
        progressB.Invoke(New UpdateProgressBarValueDelegate(AddressOf UpdateProgressBarValue), New Object() {progressB, value})
        Return
    End If

    progressB.Value = value
    progressB.Update()
End Sub

Delegate Sub UpdateProgressBarMaxDelegate(ByVal progressB As ProgressBar, ByVal max As Integer)

Public Sub UpdateProgressBarMax(ByVal progressB As ProgressBar, ByVal max As Integer)
    'If not on main thread then
    If progressB.InvokeRequired Then
        progressB.Invoke(New UpdateProgressBarMaxDelegate(AddressOf UpdateProgressBarMax), New Object() {progressB, max})
        Return
    End If

    progressB.Maximum = max
    progressB.Update()
End Sub

Delegate Sub CloseThisFormDelegate()

Public Sub CloseThisForm()
    'If not on main thread then
    If Me.InvokeRequired Then
        Me.Invoke(New CloseThisFormDelegate(AddressOf CloseThisForm), New Object() {})
        Return
    End If

    Me.Close()
End Sub

Private Sub BytesPerSecond()
    While DownloadFile
        NumberOfBytesInThisSecond = 0
        Sleep(1000)
        'ChangeText(Label3, NumberOfBytesInThisSecond / (1024 * 1024) & "MB/s")

        If NumberOfBytesInThisSecond < 1024 Then
            ChangeText(Label3, "Downloaded " & " @ " & NumberOfBytesInThisSecond & "B/s")
        ElseIf NumberOfBytesInThisSecond < 1024 * 1024 Then
            ChangeText(Label3, "Downloaded " & " @ " & Math.Round(NumberOfBytesInThisSecond / 1024, 2) & "KB/s")
        Else
            ChangeText(Label3, "Downloaded " & " @ " & Math.Round(NumberOfBytesInThisSecond / (1024 * 1024), 2) & "MB/s")
        End If

        ' ChangeText(Label3, "Currently downloading")
    End While
End Sub

Private Sub NoButton_Click(sender As Object, e As EventArgs) Handles NoButton.Click
    Me.Close()


 End Sub
End Class

服务器代码

Public Class ClientDownloadManage
    Dim ClientToManage As TcpClient
    Dim ClientManageThread As Thread
    Dim NumberOfBytes As ULong = 0
    Dim PortNumber As ULong
    Dim NetStream As NetworkStream

    Dim IntInd As Integer
    Dim ContinueSend As Boolean = True

    Public Sub New(ByVal ClientInst As TcpClient, ByVal IndPass As Integer)
        ClientToManage = ClientInst
        PortNumber = MyPorts.LicPorts.Ports(IndPass).PortNumber
        IntInd = IndPass
        ClientManageThread = New Thread(AddressOf Start_It)
        ClientManageThread.Name = "Communicating"
        ClientManageThread.IsBackground = True
        NetStream = ClientToManage.GetStream
        ClientManageThread.Start()
    End Sub

    Private Sub Start_It()
        GetBytes("C:\HoldIt")
        SendEachFileInDir("C:\HoldIt", "C:\HoldIt")
        MyPorts.LicPorts.Ports(IntInd).Available = True
    End Sub


    Private Sub SendEachFileInDir(ByVal path As String, ByVal path1 As String)
        Dim buff2(0) As Byte

        For Each foundfile As String In My.Computer.FileSystem.GetFiles(path)
            If ContinueSend = False Then
                Exit Sub
            End If

            Dim fstm As Stream = New FileStream(foundfile, FileMode.Open, FileAccess.Read)
            Dim buffer(65000 - 1) As Byte
            Dim size As ULong  'number of bytes
            size = fstm.Length


            Dim ByteSize() As Byte = BitConverter.GetBytes(size)
            Dim ByteTotalNumber() As Byte = BitConverter.GetBytes(NumberOfBytes)
            Dim PortNumberBytes() As Byte = BitConverter.GetBytes(PortNumber)
            Dim filenamebytes() As Byte = System.Text.Encoding.ASCII.GetBytes(Mid(foundfile, path1.Length + 1))

            Dim SendBytes(UBound(ByteSize) + UBound(filenamebytes) + UBound(ByteTotalNumber) + UBound(PortNumberBytes) + 4) As Byte
            Dim count As Integer = 0

            For i = 0 To UBound(ByteSize)
                SendBytes(count) = ByteSize(i)
                count += 1
            Next

            For i = 0 To UBound(ByteTotalNumber)
                SendBytes(count) = ByteTotalNumber(i)
                count += 1
            Next

            For i = 0 To UBound(PortNumberBytes)
                SendBytes(count) = PortNumberBytes(i)
                count += 1
            Next

            SendBytes(count) = filenamebytes.Length
            count += 1

            For i = 0 To UBound(filenamebytes)
                SendBytes(count) = filenamebytes(i)
                count += 1
            Next


            SendFile(foundfile, fstm, PortNumber, NetStream, SendBytes)
            fstm.Close()

        Next

        If ContinueSend = False Then
            Exit Sub
        End If

        If My.Computer.FileSystem.GetDirectories(path).Count > 0 Then
            For Each Dir As String In My.Computer.FileSystem.GetDirectories(path)
                SendEachFileInDir(Dir, path1)
            Next
        End If
    End Sub

    Private Sub GetBytes(ByVal path As String)


        For Each foundfile As String In My.Computer.FileSystem.GetFiles(path)
            Dim pstm As Stream = New FileStream(foundfile, FileMode.Open, FileAccess.Read)
            NumberOfBytes += pstm.Length
            pstm.Close()
        Next

        If My.Computer.FileSystem.GetDirectories(path).Count > 0 Then
            For Each Dir As String In My.Computer.FileSystem.GetDirectories(path)
                GetBytes(Dir)
            Next
        End If

    End Sub

    Private Sub SendFile(ByVal foundfile As String, ByVal fstm As FileStream, ByVal PortNumber As Integer, ByVal NetStream As NetworkStream, ByVal SendBytes() As Byte)
        Dim count As Integer = 0
        'Dim SendFileClient As New TcpClient
        'Dim netsStream As NetworkStream
        Dim Buffer(10024 - 1) As Byte
        Dim buff2(0) As Byte
        Dim AlreadyReceivedBytes(7) As Byte
        Dim AlreadyReceived As ULong
        Dim bytesreadsum As ULong = 0
        Dim workStream As NetworkStream
        Dim ServerInst As TcpListener

        Try
            ServerInst = New TcpListener(PortNumber)
            ServerInst.Start()
            Dim ClientInst As TcpClient
            NetStream.Write(SendBytes, 0, SendBytes.Length)
            ClientInst = ServerInst.AcceptTcpClient
            'MyPorts.LicPorts.Ports(IntInd).client = ClientInst
            workStream = ClientInst.GetStream
            NetStream.Read(AlreadyReceivedBytes, 0, 8)

            AlreadyReceived = BitConverter.ToInt64(AlreadyReceivedBytes, 0)

            If AlreadyReceived <> 0 Then
                fstm.Position = AlreadyReceived
            End If

            Do While True
                'ReDim Buffer(10024 - 1)
                ReDim Buffer(1024 - 1)

                Dim bytesRead As Integer = fstm.Read(Buffer, 0, Buffer.Length)

                Dim CountIt As Integer = 0

                If bytesRead = 0 Then
                    Exit Do
                End If

                bytesreadsum += bytesRead

                ReDim Preserve Buffer(bytesRead - 1)
                workStream.Write(Buffer, 0, Buffer.Length)
                count += 1
            Loop
            NetStream.Read(buff2, 0, buff2.Length)
            ServerInst.Stop()

        Catch ex As System.IO.IOException
            'client stopped downloading
            ContinueSend = False
            ServerInst.Stop()

            MyPorts.LicPorts.Ports(IntInd).Available = True
            Exit Sub
        End Try


    End Sub
End Class

Public Structure Port
    Dim PortNumber As Integer
    Dim Available As Boolean
End Structure

Public Structure Ports
    Dim Ports() As Port
End Structure

Public Structure LicensePorts
    Dim LicPorts As Ports
End Structure


 Public Sub processForDownload()

    Dim ServerInst As New TcpListener(8001)
    Dim ClientInst As TcpClient
    Dim count As Integer = 0
    Dim PortNumber

    ServerInst.Start()

    While True
        count += 1
        ClientInst = ServerInst.AcceptTcpClient


        PortNumber = FindValidPort()
        If PortNumber >= 0 Then
            MyPorts.LicPorts.Ports(PortNumber).Available = False
            Dim Client_new As New ClientDownloadManage(ClientInst, PortNumber)
        Else
            ClientInst.Close()
        End If

    End While
End Sub

0 个答案:

没有答案