0

I am currently writing a client/server application and need to send files (music, video, text, and any other kind) from the server to the client. Currently, I wrote the two following functions:

let sendFile (client:TcpClient) (srcFilePath:string) = 
    let formatter = new BinaryFormatter()

    // Deserialize message content to obj
    use mStream = new MemoryStream()
    (   
        use fStream = File.OpenRead srcFilePath
        fStream.CopyTo mStream 
    )
    let deserializedContent = formatter.Deserialize mStream

    // Create and serialize message into network stream
    let message = { Type = FileSync; Content = Some deserializedContent }
    formatter.Serialize (client.GetStream (), message)

Which sends the file to the client, and on the client's side to receive it:

let readStreamToFile (client:TcpClient) outputPath =
    let formatter = new BinaryFormatter()

    try
        let message = (formatter.Deserialize (client.GetStream ())) :?> Message
        match message.Type with
        | FileSync ->
            use fileStream = File.Open(outputPath, FileMode.Create)
            match message.Content with
            | Some content ->
                formatter.Serialize (fileStream, message.Content)
            | None ->
                failwith "There was no content in the FileSync message!!!"
        | _ ->
            ()
    with
    | :? InvalidCastException as ex ->
        failwith "Message format unknown!!!"

I am getting the following exception when calling formatter.Deserialize mStream:

System.Runtime.Serialization.SerializationException: End of Stream encountered before parsing was completed.

If I bypass copying the FileStream to the MemoryStream, and call formatter.Deserialize fStream instead, I am getting the following exception at the same location:

System.Runtime.Serialization.SerializationException: The input stream is not a valid binary format. The starting contents (in bytes) are: bytes

Why is my BinaryFormatter not able to deserialize my file content?

EDIT:

To ensure that my stream contains bytes, I have also tried the following, but I am getting the same The input stream is not a valid binary format exception:

// Deserialize message content to obj
let fileBytes = File.ReadAllBytes srcFilePath
use mStream = new MemoryStream()
mStream.Write (fileBytes, 0, fileBytes.Length)
mStream.Position <- (int64)0
let deserializedContent = formatter.Deserialize mStream
2
  • You're call to formatter.Deserialize mStream happens after a use scope, so at that time, mStream will be disposed of. I wonder why you don't get an ObjectDisposedException... Commented Aug 25, 2016 at 5:33
  • It might be how I have written it that is a bit unclear, but it is actually the filestream that is getting disposed and only used between the parenthesis. Commented Aug 26, 2016 at 1:17

1 Answer 1

1

If your source files are music, video, etc, then their content is not serialized by .NET. Thus, deserializing them won't work, which is why the exception is thrown. You should just read the files as they are, without deserializing:

let sendFile (client:TcpClient) (srcFilePath:string) = 
    let formatter = new BinaryFormatter()

    let fileContent = File.ReadAllBytes srcFilePath

    // Create and serialize message into network stream
    let message = { Type = FileSync; Content = Some fileContent }
    formatter.Serialize (client.GetStream (), message)

Consistent with this, you should not serialize the file content on the client side:

let readStreamToFile (client:TcpClient) outputPath =
    let formatter = new BinaryFormatter()

    try
        let message = (formatter.Deserialize (client.GetStream ())) :?> Message
        match message.Type with
        | FileSync ->
            match message.Content with
            | Some content ->
                File.WriteAllBytes(outputPath, content)
            | None ->
                failwith "There was no content in the FileSync message!!!"
        | _ ->
            ()
    with
    | :? InvalidCastException as ex ->
        failwith "Message format unknown!!!"

Note that I have changed the type of Content from obj option to byte[] option.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.