2013-02-22 53 views
1

這可以看作是我以前thread.Receving數據從二進制作家網絡流

我做了我的文件共享應用的一些發展和固定的東西的延續,但我現在面臨的另一個問題。我猜這不是那麼難,只是我現在用腦力來解決這個問題。我相信這可以以更好的方式完成。

下面是我收到的錯誤的屏幕截圖。

正如你可以在截圖中看到,該FileName變量中有一定價值。它是我發送的文件的名稱。如果您注意到,變量包含ello.cpp,它必須是hello.cpphello.cpp是要發送的文件的名稱。尾隨的字符是文件的內容。尾隨字符不再是問題,只要我能正確解決這個問題,文件名將是唯一存儲在變量中的文件名。

錯誤發生在網絡流的讀取過程中。我想要實現的是,我想阻止網絡流在不是日誌消息時讀取。我需要將networkstream.read放在某個位置,以便它不會佔用文件的第一個字母。也許某種過濾?或者如果可能只有一個代碼可以獲取日誌消息和文件名,那將非常棒。文件名是使用二進制編寫器發送的,我嘗試使用網絡流來檢索文件名,但它不起作用。我在這裏錯過了什麼嗎?

以下是服務器部分的代碼。

Try 

     While FileSharingStarted 

      If CBool(ClientSocket.Available) Then 

       Dim ByteData(ClientSocket.ReceiveBufferSize) As Byte 

       'This reading of the stream here causes the problem. That's why the 
       'file name isn't read properly. This reading part here is actually 
       'intended for the logging part. What happens is that when the string 
       'for the logging part is sent by the client side, this is being read 
       'using this. But when a file is sent, it is read here in this part 
       'that's why when the algorithm for retrieving the file name below 
       'kicks in, the first letter of the file name is missing, and ruins 
       'the whole thing. 
       networkStream.Read(ByteData, 0, CInt(ClientSocket.ReceiveBufferSize)) 

       fileLogMessage = Encoding.ASCII.GetString(ByteData) 
       Dim ConnectionStatus() As String 
       ConnectionStatus = fileLogMessage.Split(CChar(" ")) 

       If fileLogMessage.Contains("is connected." & Environment.NewLine) Then 

        'Creates a log when the user connects. 

       ElseIf fileLogMessage.Contains("is disconnected." & Environment.NewLine) Then 

        'Creates a log when the user disconnects. 

       Else 

        'Algorithm for receiving the files. 

        Dim FileName, FilePath As String 
        Dim FileLength As Long 

        'This part here conflicts with the `networkstream.read` above 
        Dim binaryReader As New BinaryReader(ClientSocket.GetStream) 
        FileName = binaryReader.ReadString() 
        FileLength = binaryReader.ReadInt64() 
        FilePath = Path.Combine(System.Environment.CurrentDirectory & "\home", FileName) 

        Dim FileData(8092) As Byte 
        Dim TotalData As Long = 0 
        Dim ReadBytes As Integer = -1 

        Using fileStream As New FileStream(FilePath, FileMode.Create, FileAccess.Write) 

         FileSharingStatusBar.Panels.Item(1).Text = "Receiving file . . ." 

         Do Until TotalData = FileLength 

          If ReadBytes = 0 Then 
           fileStream.Close() 
           FileTransferInterrupted = True 
           Exit Do 
          Else 
           ReadBytes = ClientSocket.GetStream.Read(FileData, 0, FileData.Length()) 
           fileStream.Write(FileData, 0, ReadBytes) 
           TotalData += ReadBytes 
          End If 

         Loop 

        End Using 

        If FileTransferInterrupted Then 

         MessageBox.Show("File transfer interrupted.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information) 
         FileSharingStatusBar.Panels.Item(1).Text = "Idle." 

        Else 

         MessageBox.Show("File received.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information) 
         FileSharingStatusBar.Panels.Item(1).Text = "Idle." 

        End If 

       End If 

      End If 

     End While 

下面是客戶端的代碼。

Try 

     Dim fileInfo As New FileInfo(txtFilePath.Text) 
     Dim binaryWriter As New BinaryWriter(fileClientSocket.GetStream()) 

     'Here's the part where it writes the file name on the 
     'stream using the binary writer 
     binaryWriter.Write(fileInfo.Name) 
     binaryWriter.Write(fileInfo.Length) 

     Using fileStream As New FileStream(txtFilePath.Text, IO.FileMode.Open, IO.FileAccess.Read) 

      Dim FileData(8092) As Byte 
      Dim ReadBytes As Integer = -1 
      FileSharingStatusBar.Panels.Item(1).Text = "Sending file . . ." 

      Do Until ReadBytes = 0 

       If CBool(fileClientSocket.Available) Then 

        MessageBox.Show("File transfer interrupted.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information) 
        Exit Sub 

       Else 

        ReadBytes = fileStream.Read(FileData, 0, FileData.Length) 
        fileClientSocket.GetStream.Write(FileData, 0, ReadBytes) 

       End If 

      Loop 

     End Using 

     txtFilePath.Text = "" 
     MessageBox.Show("File sent.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information) 
     FileSharingStatusBar.Panels.Item(1).Text = "Idle." 

    Catch ex As Exception 

     MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Information) 

End Try 

建議將不勝感激。

在此先感謝! :)

回答

0

我想出瞭如何解決它。感謝我的一位朋友在Facebook上的建議,一位程序員。我做了什麼,發送了一些字符串,告訴服務器部分接收文件。現在都很好。 :)

我也想承認史蒂文Doggart所有的努力和建議,特別是關於SOAP。

非常感謝好先生! :)

0

我會建議總是讀取網絡流中的所有數據並將其附加到通信緩衝區/隊列中。每次將更多數據添加到隊列中時,請分析整個隊列中的數據以查看它是否包含任何完整的消息。如果是這樣,請將其從隊列中移除,然後處理它們。例如,你可以創建一個實現這樣一個接口的類:

Public Interface IIncomingDataBuffer 
    Sub Append(ByVal data() As Byte) 
    Event MessageReceived As EventHandler(Of MessageEventArgs) 
End Interface 

這將是更容易實現這樣的功能,如果消息是固定的寬度或通過預定義符隔開。另外,我建議在每個消息的開頭都有一個頭部塊,其中包含消息類型字符(如果沒有其他消息)。

+0

謝謝你的回覆。這似乎是一個不錯的主意。但事情是,我只能這樣做,如果我能夠得到正在發送的文件的文件名。只要我無法檢索網絡流上的文件名(因爲它是用二進制寫入器編寫的),我不能這樣做,因爲我不知道如何在寫入時使用網絡流檢索文件名二進制作家。此外,我只需要對代碼進行適當的重構,特別是'networkstream.read'部分,以便在發送文件時不會發生干擾。 – 2013-02-22 15:38:40

+0

那麼,據我瞭解,你正在發送兩種不同類型的消息:日誌消息和文件傳輸消息。在日誌消息中,您只有一個有效負載字段:要記錄的文本。但在文件傳輸消息中,您有三個有效負載字段:文件名,文件大小和文件內容。因此,您不僅需要定義如何確定每封郵件的開始和結束位置,而且還需要定義如何確定郵件中每個字段的開始和結束位置。 – 2013-02-22 16:05:38

+0

你在本質上做的是定義你自己的協議。這絕不是一個不可能完成的任務,但它是設計中非常關鍵的一步,不能簡單地跳過或掩蓋。如果你不想花時間去設計一個好的協議,我建議你只使用一個已經存在的協議,比如SOAP。 .NET框架內置了用於處理SOAP的類,而Visual Studio IDE甚至提供了方便的WCF和ASMX Web服務工具,用於開發基於SOAP的應用程序的客戶端和服務器端。 – 2013-02-22 16:07:44