Previous Data Remains on the Network Stream

纵饮孤独 提交于 2019-12-11 05:56:07

问题


I'm currently building a file transfer application with some logging features. What it does is, every time a client connects or disconnects it sends logs (string message) to the server. The logging part is working fine but when I try to send files, the program messes up.

It seems that this is purely a server side issue. What happens is that the previous data; which is the string message for logging, sent from the client seems get stuck on the network stream. When I try to send a file after connecting to the server, I get an error which says, illegal characters in path.

Here's a screenshot of the error.

I believe that this happens because, as you can see on the screenshot above in the FileName variable, a part of the string ("is connected.") which was sent when the client connected was stuck on the network stream. hello.cpp is the name of the file being sent.

Here's the code.

Dim ClientSocket As TcpClient = CType(tcpSocket, TcpClient)

Dim networkStream As NetworkStream = ClientSocket.GetStream() 'This stream is
'for the logging part. This part here, I think causes the error because when I
'remove this and the conditions for the logging part, leaving the file sharing
'algorithm alone, the whole program works.

While FileSharingStarted

    If CBool(ClientSocket.Available) Then
        Dim ByteData(ClientSocket.ReceiveBufferSize) As Byte
        networkStream.Read(ByteData, 0, CInt(ClientSocket.ReceiveBufferSize))
        fileLogMessage = Encoding.ASCII.GetString(ByteData)

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

            'This block here is for logging purposes. It receives the string 
            'message sent by the client when it connects and does some stuffs.

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

            'This block here is for logging purposes again. It receives the 
            'string message sent by the client when it disconnects and then 
            'does some stuffs.

        Else

            'This part is for receiving the file sent by the client.

            Dim FileName, FilePath As String
            Dim FileLength As Long
            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
                    ReadBytes = ClientSocket.GetStream.Read(FileData, 0, FileData.Length())
                    FileStream.Write(FileData, 0, ReadBytes)
                    TotalData += ReadBytes
                Loop
            End Using

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

            FileSharingStatusBar.Panels.Item(1).Text = "Idle."
        End If
    End If

End While

I'm just curious why does this happen. Am I missing something here? Any explanation or suggestion to sort this one out would be highly appreciated. Please enlighten me. :)


回答1:


You are correct in your assumption that after you read the data, the next time you read from the stream, the same data will not be returned again. Your position in the stream is automatically moved forward every time you read from the stream. The problem, though, seems to be that by the time the server reads from the stream, the client has already sent multiple messages (in your example, a log message followed by a file transfer message). When your server application reads the stream, it is not parsing apart the multiple messages and handling them individually. Also, as I mentioned in a comment above, your server application needs to handle the fact that it may receive partial messages as well. It needs to buffer the communication as it comes in and only process the messages once it has received the complete message data.




回答2:


From my experience with network streams, I believe you are right on your assumption of the stream clearing itself out [1].

One other thing I have observed with network streams is that if one or more successive writes are performed, those writes are all put together and will not be cleared until the receiving end reads the entire stream to the end. What this means for you is that it may not be possible to distinguish between messages if more than one message is sent before the recipient reads the stream.

One way around this is to insert placeholders in your stream to mark the start and/or end of distinct messages. If that is done, your program will be able to determine where one chunk of data starts and where it ends. Implementing placeholders, in my opinion, should free you of the trouble you are currently experiencing.

Sample Implementation
Note: Code in italics may be incorrect

Dim placeholder As Byte() = New Byte() {&H00, &H01, &HFE, &HFF}
Dim message As New List(Of Byte)()
Dim data As Byte()

Do While True
    data = stream.ReadBytes(1024)
    If data.Skip(data.Length - placeholder.Length).SequenceEquals(placeholder) Then
        message.AddRange(data.Take(data.Length - placeholder.Length)
        Exit Do
    Else
        message.AddRange(data)
    End If
Loop

' do something with the message read

What this does is that it reads the stream until it reads a chunk of data which ends with the placeholder signature then it stops and does something with the message that has been read from the stream.

Of course in your implementation you could have multiple concatenated messages so you'll have to have a way of preserving bytes from the next message that were 'accidentally' read. You also will have to do a pattern matching of the chunk of data read instead of checking if the beginning/end matches the placeholder.



来源:https://stackoverflow.com/questions/14978965/previous-data-remains-on-the-network-stream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!