Link to home
Start Free TrialLog in
Avatar of simonallenuk
simonallenuk

asked on

Byte array cannot be converted to String for sending over UDP

Hi,

Basically I'm reading in a file (wav, text, jpg etc) for transfer over UDP

=============
Dim objBr As New BinaryReader(File.OpenRead(FilenameGoesHere))
Dim bytFile As Byte() = objBr.ReadBytes(objBr.BaseStream.Length)
objBr.Close()
xSock.UDP_Send(txtIPIn.Text, 10090, bytFile)
=============

Then I try to send the array (stored in bytFile) I get this message:

"Value of type '1-dimensional array of Byte' cannot be converted to 'String'."

I've tried a few different things but nothing works. I am assuming that converting a binary file to string isn't a good idea. Is there a way round this or an alternate method of sending the files using UDP rather than TCP/IP ?

Simon
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Where does xSock.UDP_Send come from?

Bob
Avatar of simonallenuk
simonallenuk

ASKER

Oops, Its a seperate class file:

====================
#Region "Imports"
Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
#End Region


Public Class xSock

#Region "Declares"
    Private Shared UDP_Client As New UdpClient
    Private Shared UDP_Server_Port As Integer
    Private Shared thdUdp As Thread
    Private Shared UDP_Server As UdpClient
#End Region

#Region "Events"
    'Public Event Close()
    Public Shared Event DataArrival(ByVal Data As String)
    Public Shared Event Sock_Error(ByVal Description As String)
#End Region


#Region "UDP"

    Public Shared Sub UDP_Send(ByVal Host As String, ByVal Port As Integer, ByVal Data As String)
        Try
            UDP_Client.Connect(Host, Port)

            Dim sendBytes As [Byte]() = Encoding.Unicode.GetBytes(Data)
            UDP_Client.Send(sendBytes, sendBytes.Length)

        Catch e As Exception
            RaiseEvent Sock_Error(e.ToString)
        End Try

    End Sub

    Public Shared Function UDP_Listen(ByVal Port As Integer) As Boolean
        Try
            UDP_Server_Port = Port
            UDP_Server = New UdpClient(Port)
            thdUdp = New Thread(AddressOf GetUDPData)
            thdUdp.Start()
        Catch e As Exception
            RaiseEvent Sock_Error(e.ToString)
        End Try

    End Function

    Private Shared Sub GetUDPData()
        Do While True
            Try
                Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Any, 0)
                Dim RData = Encoding.Unicode.GetString(UDP_Server.Receive(RemoteIpEndPoint))
                RaiseEvent DataArrival(RData)
                If RData = "CloseMe" Then Exit Do
                Thread.Sleep(0)
            Catch e As Exception
                RaiseEvent Sock_Error(e.ToString)
            End Try
        Loop
    End Sub

    Public Shared Sub CloseSock()
        Dim s As New txtserver
        UDP_Send(s.txtIPOut.Text, UDP_Server_Port, "CloseMe")
        Thread.Sleep(30)
        UDP_Server.Close()
        thdUdp.Abort()
    End Sub
#End Region

End Class
===================
In this line, you should be passing data as String, but you are passing a byte array:
Public Shared Sub UDP_Send(ByVal Host As String, ByVal Port As Integer, ByVal Data As String)

Implicit conversion are not allowed for this--you need an explicit conversion:

Dim dataString As String = Encoding.ASCII.GetString(bytFile)

You can also use different encoding, such as Unicode, UT8, etc.

Bob

Thanks to TheLearnedOne I can now send text files over UDP but unfortunatly I when I try doing it with .wav files they:

a) Using ASCII are the same file size but not a valid audio file
or
b) Using UTF8 are not the same file size and aren't valid audio files

Any Ideas ?
D'oh.  Change the parameter to ByVal Data As Byte().   Then, don't convert from byte to string, just Send with the byte array, which is what the UDPClient.Send takes as a parameter anyway.

Bob
Oh yea Unicode makes a file twice as big but doesn't work.

I have the wav file stored in a byte array... but its that array that I don't know how to transfer over UDP.
What I am trying to say is that you are converting back and forth from byte array to string to byte array, and that is not necessary:

UDPClient.Send:

Public Function Send(Byte(), Integer) As Integer   <-- Byte array.

Just keep everything as Byte array, and do use any encoding.

Bob
Just tried that "ByVal Data As Byte()" but i get:

'1-dimensional array of Byte' cannot be converted to 'Byte'.
Delete this line:

 Dim sendBytes As [Byte]() = Encoding.Unicode.GetBytes(Data)

Also, can I see the code that you have now?

Bob
receiver:
=====
 xSock.UDP_Send(txtIPIn.Text, 10090, dataString)
        lstMsg.Items.Add(vMsg)    <-- List box just so i can see whats being sent before it goes to a file
        Dim fs As New IO.FileStream(txtOutput.Text, IO.FileMode.Create)
        Dim bw As New IO.BinaryWriter(fs)
        'Dim temp As Byte = Encoding.Convert(dataString, bytFile)
        bw.Write(vMsg)
        bw.Close()

sender:
=====
        Dim objBr As New BinaryReader(File.OpenRead(txtInput.Text))
        Dim bytFile As Byte() = objBr.ReadBytes(objBr.BaseStream.Length)
        objBr.Close()
         xSock.UDP_Send(txtIPIn.Text, 10090, bytFile)

cvSock.vb
======
#Region "UDP"

    Public Shared Sub UDP_Send(ByVal Host As String, ByVal Port As Integer, ByVal Data As Byte)
        Try
            UDP_Client.Connect(Host, Port)

            'Dim sendBytes As [Byte]() = Encoding.Unicode.GetBytes(Data)
            'UDP_Client.Send(sendBytes, sendBytes.Length)

       <-- Unsure how to add in your code here!-->
       UDPClient.Send:
       Public Function Send(Byte(), Integer) As Integer   <-- Byte array
       <--    --   --   --  --  --  --  --  --  --  -->

        Catch e As Exception
            RaiseEvent Sock_Error(e.ToString)
        End Try

    End Sub
Public Shared Sub UDP_Send(ByVal Host As String, ByVal Port As Integer, ByVal Data As Byte())
        Try
            UDP_Client.Connect(Host, Port)
       UDP_Client.Send(sendBytes, sendBytes.Length)
        Catch e As Exception
            RaiseEvent Sock_Error(e.ToString)
        End Try

    End Sub
Sorry for the confusion.

Bob
Since sendBytes is declared and using

Dim sendbytes As Byte

doesn't work for sendBytes.Length

What should I use?
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ok nearly there

In the cvSock.vb file there is a section:

Public Shared Sub CloseSock()
        Dim s As New txtserver
        UDP_Send(s.txtIPOut.Text, UDP_Server_Port, "CloseMe")
        Thread.Sleep(30)
        UDP_Server.Close()
        thdUdp.Abort()
    End Sub

Instead of "CloseME" which is a string what can I put in there! as its now suppose to be a byte array.
You had something close before:

Dim bytClose() As Byte = System.Text.Encoding.AsciiEncoding.GetBytes("CloseMe")

UDPSend(s.txtIPOut.Text, UDP_Server_Port, bytClose)

After some changes to other code I have the program will compile but the input/output from the files transfered look like this, even with plain text files:

瑨灴⼺眯睷攮灸牥獴攭捸慨杮
You can use overloads for the same routine name.  Therefore keep both routines:

Public Shared Sub UDP_Send(ByVal Host As String, ByVal Port As Integer, ByVal Data As String)
and
Public Shared Sub UDP_Send(ByVal Host As String, ByVal Port As Integer, ByVal Data As Byte())

then you can easily call both:
  UDP_Send(s.txtIPOut.Text, UDP_Server_Port, "CloseMe")
and
  xSock.UDP_Send(txtIPIn.Text, 10090, bytFile)

and you don't need to do any additional encoding.

--- --- ---
The receiving end is using Unicode encoding (to decode):
    Dim RData = Encoding.Unicode.GetString(UDP_Server.Receive(RemoteIpEndPoint))
    RaiseEvent DataArrival(RData)
    If RData = "CloseMe" Then Exit Do
Therefore you MUST use Unicode encoding when sending the "CloseMe", otherwise it'll never know when it's the end of the data.  (P.S.  I'd call that a bug anyway.  Just try sending some real data that's the string "CloseMe" and your server will prematurely terminate reception.)

After that, you'll need to put your debugging skills to work.

--- --- ---
Here's a little snippet that might be handy.  (It could use lots of improvement/extensions,too.)

    Function BytesToString(ByVal bytes As Byte(), Optional ByVal AsHex As Boolean = True) As String
        Dim sb As New System.Text.StringBuilder
        Dim sw As New System.IO.StringWriter(sb)
        Dim nl As String = System.Environment.NewLine
        Dim count As Integer = 0
        Dim blockSize As Integer = 16
        Dim blockFormat As String
        Dim itemFormat As String

        If AsHex Then
            blockFormat = "{0:X4}: "
            itemFormat = " {0:X2}"
        Else
            blockFormat = "{0,5}: "
            itemFormat = " {0,3}"
        End If

        For blockStart As Integer = 0 To bytes.Length Step blockSize
            sw.Write(String.Format(blockFormat, blockStart))
            For index As Integer = blockStart To blockStart + blockSize - 1
                If index < bytes.Length Then
                    sw.Write(String.Format(itemFormat, bytes(index)))
                End If
            Next
            sw.WriteLine()
        Next

        Return sw.ToString
    End Function

Sample Output:
0000:  48 00 65 00 6C 00 6C 00 6F 00 2C 00 20 00 74 00
0010:  68 00 65 00 72 00 65 00 21 00 20 00 20 00 41 00
0020:  42 00 43 00 44 00 45 00 46 00 47 00 48 00 49 00
0030:  4A 00 4B 00 4C 00 4D 00 4E 00 4F 00 50 00 51 00
0040:  52 00 53 00 54 00 55 00 56 00 57 00 58 00 59 00
0050:  5A 00
Also, you'll want to rewrite GetUDPData() because it's decoding right away, so all your nice unencoded bytes are immediately being decoded.  That's not what you want.  Since they were never encoded, you get garbage.  I suggest something like this:

    Private Shared Sub GetUDPData()
        Do While True
            Try
                Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Any, 0)
                Dim RBytes As Byte() = UDP_Server.Receive(RemoteIpEndPoint)
                Dim RData = Encoding.Unicode.GetString(RBytes)
                RaiseEvent DataArrivalBytes(RBytes)
                RaiseEvent DataArrival(RData)
                If RData = "CloseMe" Then Exit Do
                Thread.Sleep(0)
            Catch e As Exception
                RaiseEvent Sock_Error(e.ToString)
            End Try
        Loop
    End Sub

Then you'll also need to write the new DataArrivalBytes event,too.  Then use the DataArrivalBytes event if you want to receive the undecoded bytes, or the DataArrival event if you want to receive a text string.
And out of the blue, streaking across the sky is Super man, come to save the day *GRIN*

You'd better watch out, Big Bad Bill is back in town.  Howdy stranger :)

Bob
Maybe its the cold I have or just my stupidty but my heads starting to spin with all this code.
The function 'BytesToString'... were does this fit in the grand scheme of things?
BytesToString would be useful for debugging to see what the actual bytes transferred are.
You said it was:  瑨灴⼺眯睷攮灸牥獴攭捸慨杮,  but that's pretty meaningless, at least to me.  BytesToString would show the actual values (represented as hex or decimal) of the bytes.  You could use it as:
  Debug.Write(BytesToString( Data ))
or use it to write to a log file.
If you made log files on both your client (sending) and your server (receiving), you should then be able to examine the logs and hopefully find some correlation between the two, if the data transfer is not working.  If the data transfer is working, you would expect identical results on both ends.

I have a slightly improved version of BytesToString that also prints the decoded string to right of the list of bytes.  Do you want it?  Output would look like this for Hex and Unicode encoding.
0000:  48 00 65 00 6C 00 6C 00 6F 00 2C 00 20 00 74 00 - Hello, t
0010:  68 00 65 00 72 00 65 00 21 00                   - here!

[  Knowing nothing about your programming knowledge, I ask ... ]  How are your debugging skills?  Are you familiar with setting/clearing breakpoints, stepping through code line by line, using watchpoints, and using the Command window?

> Maybe its the cold ...
Aaaah, shake it off.  We can slow down and go step by step.  Just keep asking clarifying questions.  I'm a bit tired and fuzzy-headed myself tonight.


Oh Great TheLearnedOne: I didn't mean to hijack the question, but I thought the "overloads" issue would really clear up some things. (And was surprised you hadn't mentioned it yet.  I was thinking you were just tired that day.) Then I had another idea, and another ...      Thanks for the welcome back.

My debugging skills are pretty much average.

This is the output (first 10 lines only) for sending a small wav file,
the receiver had only half of the total lines from the sender:

Sender:
=====
0000:  52 49 46 46 F6 44 00 00 57 41 56 45 66 6D 74 20
0010:  10 00 00 00 01 00 01 00 80 BB 00 00 80 BB 00 00
0020:  01 00 08 00 64 61 74 61 D1 44 00 00 7F 7F 7F 7F
0030:  7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
0040:  7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
0050:  7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
0060:  7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
0070:  7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
0080:  7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
0090:  7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F

Receiver:
======
0000:  3F 3F 3F 00 3F 3F 3F 3F 10 00 01 01 3F 00 3F 00
0010:  01 08 3F 3F 3F 00 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F
0020:  3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F
0030:  3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F
0040:  3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F
0050:  3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F
0060:  3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F
0070:  3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F
0080:  3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F
0090:  3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F

What I did notice was the client that gets the file is looking for string values (before I added in the 2nd last line)

Private Sub OnDataRival(ByVal vMsg As String)
        lstMsg.Items.Add(vMsg)
        Dim fs As New IO.FileStream(txtOutput.Text, IO.FileMode.Create)
        Dim bw As New IO.BinaryWriter(fs)
        bw.Write(vMsg)
        bw.Close()

        '-- check output directly after reading in
        Dim msgdata() As Byte = System.Text.Encoding.ASCII.GetBytes(vMsg)
        Debug.Write(BytesToString(msgdata))
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
> the receiver had only half of the total lines from the sender

Unicode is a double-byte encoding.  Therefore this (almost certainly) indicates there's some mismatch with encoding.  

And yep, there it is.  Your second-to-last line is doing ASCII encoding.
Try just changing it to Unicode encoding.

[Theory]

Think of this whole data transmission process in the shape of a "U".  The sender goes down the left-hand edge, the data

goes across the wire along the bottom. and the receiver gets the data and goes up the right-hand edge.  Any actions

that the sender does (down the left) must be EXACTLY reversed by the receiver (up the right).  So in general, for any

transmission process, if the sender performs processes A, B, C, then D to put the data on the wire, then the sender

must exactly reverse that:  D', C', B', and finally A'.

In      Out
A        A'
B        B'
C        C'
D        D'
 ===>

In your case, you want to send RAW UNCHANGED data bytes, so you want to avoid encoding and avoid Strings.  This

actually makes things simpler.  You can think of this as skipping steps B and C (and therefore also C' and B').

A: Read data bytes directly from file into byte array.
D: Send raw bytes.
---=== across the wire ===---
D': Receive raw bytes in a byte array.
A': Store raw bytes from byte array to file.

Part of your problem is that the code you're starting with (UPD_Send and GetUDPData) are designed to send strings, not

raw bytes, so they're doing encoding that you don't need or want.  The key thing is you need to write replacements that

DO NO ENCODING AND NO DECODING.  They just use raw bytes in a byte array.

Definition: Raw -- [In this context] unchanged, unprocessed, with no additional information or processsing
http://www.google.com/search?hl=en&q=define%3Araw

... So ...
[Implementation]

Process A:  Read data bytes directly from file into byte array.

        [your posted code]
        Dim objBr As New BinaryReader(File.OpenRead(txtInput.Text))
        Dim bytFile As Byte() = objBr.ReadBytes(objBr.BaseStream.Length)
        objBr.Close()

Process D:  Send raw bytes.

         xSock.UDP_Send(txtIPIn.Text, 10090, bytFile)       ' from your post above.
         xSock.UDP_Send(txtIPIn.Text, 10090, "CloseMe")     ' from farsight.

This uses TheLearnedOne's posted code for UDP_Send to send raw bytes, as well as your original UDP_Send to send the

Unicode-encoded termination string, which is expected and necessary for GetUDPData to properly terminate.

    [TheLearnedOne's posted code]
    Public Shared Sub UDP_Send(ByVal Host As String, ByVal Port As Integer, ByVal Data As Byte())
        Try
            UDP_Client.Connect(Host, Port)
            UDP_Client.Send(sendBytes, sendBytes.Length)
        Catch e As Exception
            RaiseEvent Sock_Error(e.ToString)
        End Try
    End Sub

    [From your original code]
    Public Shared Sub UDP_Send(ByVal Host As String, ByVal Port As Integer, ByVal Data As String)
        Try
            UDP_Client.Connect(Host, Port)

            Dim sendBytes As [Byte]() = Encoding.Unicode.GetBytes(Data)
            UDP_Client.Send(sendBytes, sendBytes.Length)

        Catch e As Exception
            RaiseEvent Sock_Error(e.ToString)
        End Try
    End Sub

Process D':  Receive raw bytes in a byte array.

    [from farsight's posted code]
    Private Shared Sub GetUDPData()
        Do While True
            Try
                Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Any, 0)
                Dim RBytes As Byte() = UDP_Server.Receive(RemoteIpEndPoint)
                Dim RData = Encoding.Unicode.GetString(RBytes)
                RaiseEvent DataArrivalBytes(RBytes)

            'NOTE: I added this call to BytesToString, which at this point
                'should be EXACTLY what was sent by the sender.
            'Since it was NOT encoded on the sender, we'll use ASCII encoding here,
            'only so we can see the first few bytes we expect in a *.WAV file: "RIFF".
                Debug.WriteLine(  BytesToString( RBytes, True, System.Text.Encoding.ASCII))

                RaiseEvent DataArrival(RData)
                If RData = "CloseMe" Then Exit Do
                Thread.Sleep(0)
            Catch e As Exception
                RaiseEvent Sock_Error(e.ToString)
            End Try
        Loop
    End Sub

Process A':  Store raw bytes from byte array to file.

  [NOT WORKING:  your most-recently posted code]
  'NOTE: I corrected an apparent typo: OnDataRival ==> OnDataArrival
  Private Sub OnDataArrival(ByVal vMsg As String)
        lstMsg.Items.Add(vMsg)
        Dim fs As New IO.FileStream(txtOutput.Text, IO.FileMode.Create)
        Dim bw As New IO.BinaryWriter(fs)
        bw.Write(vMsg)
        bw.Close()

        '-- check output directly after reading in
        'NOTE: I changed from ASCII to Unicode encoding.
        Dim msgdata() As Byte = System.Text.Encoding.Unicode.GetBytes(vMsg)
        Debug.Write(BytesToString(msgdata))
   End Sub

This is not working primarily because you're processing the String which is provided by the DataArrival Event, which

has already been Unicode-decoded in GetUDPData.  It's got encoding we dont' need or want.

[What's remaining to do ...]
You need to add a new event that gives you the raw bytes instead of the string.  In other words, implement the code for

DataArrivalBytes.  Add this near the top of the xSock class (near DataArrival):

    Public Shared Event DataArrivalBytes(ByVal bytes As Byte())

Delete your OnDataArrival routine, and put this instead:

  Private Sub OnDataArrivalBytes(ByVal bytes As Byte())
        'NOTE: Seems like a bug to add the bytes of the *wav file to a listbox ... so don't.
        'Currently we're sending only the file, but NOT the file name.
        'lstMsg.Items.Add(vMsg)

        Dim fs As New IO.FileStream(txtOutput.Text, IO.FileMode.Create)
        Dim bw As New IO.BinaryWriter(fs)
        bw.Write(bytes)
        bw.Close()

        '-- check output directly after reading in
        'NOTE: This should write exactly the same thing that was
      ' written in GetUDPData
        Debug.WriteLine(  BytesToString( RBytes, True, System.Text.Encoding.ASCII))
   End Sub

And in the Form_Load (or other initialiation) routine, add:
  AddHandler xSock.DataArrival, AddressOf OnDataArrivalBytes
and remove:
  AddHandler xSock.DataArrival, AddressOf OnDataRival

---

For Reference:
It appears the original UDP code is from:
http://www.codeproject.com/Purgatory/The_UDP_under_VBNET.asp
Oops, that last part should be:

And in the Form_Load (or other initialiation) routine, add:
  AddHandler xSock.DataArrivalBytes, AddressOf OnDataArrivalBytes        ' *** changed this line ***
and remove:
  AddHandler xSock.DataArrival, AddressOf OnDataRival
========================================
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
            Dim objBr As New BinaryReader(File.OpenRead(txtInput.Text))
            Dim bytFile As Byte() = objBr.ReadBytes(objBr.BaseStream.Length)
            objBr.Close()
            Debug.WriteLine(BytesToString(bytFile))
            xSock.UDP_Send(txtIPIn.Text, 10090, bytFile)    <------
            xSock.UDP_Send(txtIPIn.Text, 10090, "CloseMe")
========================================

Ok I think i've got everything back in now... But i'm back to getting the compile error on "bytFile" saying:
Value of type '1-dimensional array of Byte' cannot be converted to 'String.

To see what I have so far: http://www.lackofpotatoes.co.uk/VB.rar
Hello,
I am trying to receive data over UDP sent from a Linux box.  the following is the structure I am trying to recover from the received data.  How do I do that?  Any help is greatly appreciated.

Struct Position
{
  double px;
  double py;
  double pz;
};
Ashali,
  Experts Exchange is all about question and answer pairs, not extended discussions.  This question has already been asked and answered.  Only the people who've commented in this question, and are still subscribed to it, will even notice you mentioned something.

Please create a new question  and ask your question.
If needed, you can put a link to this question as related information.
Everyone reads the new questions, so you'll get the attention you need.