Получение данных от двоичного устройства записи в сетевой поток
Это можно рассматривать как продолжение моей предыдущей темы.
Я сделал некоторые разработки и исправил некоторые вещи в своем приложении для обмена файлами, но теперь я столкнулся с другой проблемой. Это не так сложно, я думаю, просто у меня сейчас не хватает умственных способностей, чтобы заняться этим. Я считаю, что это можно сделать лучше.
Вот скриншот ошибки, которую я получаю.
Как вы можете видеть на скриншоте, FileName
переменная имеет некоторые значения в нем. Это имя файла, который я отправляю. Если вы заметили, переменная содержит ello.cpp, это должен быть hello.cpp. hello.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
Предложения будут высоко оценены.
Заранее спасибо!:)
2 ответа
Я разобрался, как это решить. Благодаря одному из предложений моего друга в Facebook, другой программист. Что я сделал, так это отправил какую-то строку, которая сигнализирует серверной части о получении файла. Теперь все хорошо.:)
Я хотел бы также поблагодарить Стивена Доггарта за все его усилия и предложения, особенно в отношении SOAP.
Большое спасибо, сэр!:)
Я бы рекомендовал всегда читать все данные в сетевом потоке и добавлять их в буфер / очередь связи. Каждый раз, когда в очередь добавляется больше данных, анализируйте данные во всей очереди, чтобы увидеть, не содержит ли они полные сообщения. Если так, удалите их из очереди и затем обработайте их. Например, вы можете создать класс, который реализует такой интерфейс:
Public Interface IIncomingDataBuffer
Sub Append(ByVal data() As Byte)
Event MessageReceived As EventHandler(Of MessageEventArgs)
End Interface
Реализовать такую функциональность будет проще, если сообщения имеют фиксированную ширину или разделены предварительно определенным разделителем. Кроме того, я бы порекомендовал иметь блок заголовка в начале каждого сообщения, который содержит, если не больше, символ типа сообщения.