CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9
  1. #1
    Join Date
    Feb 2010
    Posts
    29

    [RESOLVED] Sending DateTime information with image

    Hello everyone,

    I want to extend my program by sending a DateTime object alongside an image object AT THE SAME TIME. Below is the working code I have thus far:

    Code:
            //Sends the image using a TcpClient
            //I want to extend this by sending a DateTime object along side the image
            public void Connect(String server, Image img)
            {
                try
                {
                    //Create TcpClient
                    string ownPort = txtOwnPort.Text;
                    int port = Convert.ToInt32(ownPort);
                    TcpClient client = new TcpClient(server, port);
                    Byte[] bytes = null;
                    
                    MemoryStream ms = new MemoryStream();
                    img.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
                    bytes = ms.ToArray();
    
                    NetworkStream stream = client.GetStream();
    
                    //Get current time
                    DateTime currentTime = DateTime.Now;
                    
                    stream.Write(bytes, 0, bytes.Length);
                    Console.WriteLine("Image sent at {0}.", currentTime.TimeOfDay);
                    Console.WriteLine("Sent {0} bytes.", bytes.Length);
    
                    //Close everything
                    stream.Close();
                    client.Close();
                }
                catch(ArgumentNullException e)
                {
                    Console.WriteLine("ArgumentNullException: {0}", e);
                }
                catch(SocketException e)
                {
                    Console.WriteLine("SocketException: {0}", e);
                }
            }
    
            //Listen for incoming packets
            //I want to extend this so it can pick up the image and the DateTime object
            public void Listen()
            {
                TcpListener server = null;
                try
                {
                    string ownPort = txtOwnPort.Text;
                    int port = Convert.ToInt32(ownPort);
    
                    IPAddress localAddr = IPAddress.Parse(txtOwnIP.Text);
    
                    server = new TcpListener(localAddr, port);
    
                    //Start listening for client requests
                    server.Start();
    
                    //Buffer for reading data
                    Byte[] bytes = new Byte[32768];
                    Image img;
                    //Enter the listening loop
                    while(true)
                    {
                        //Perform a blocking call to accept requests
                        TcpClient client = server.AcceptTcpClient();
    
                        img = null;
    
                        //Get a stream object for reading and writing
                        NetworkStream stream = client.GetStream();
    
                        int i;                    
    
                        //Loop to receive all the data sent by the client
                        while((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            DateTime currentTime = DateTime.Now;
                            Console.WriteLine("Recieved {0} bytes at {1}", bytes.Length, currentTime.TimeOfDay);
    
                            //DateTime delayTime = sentTime.Millisecond - currentTime.Millisecond;
      
                            //Convert byte array to image
                            img = byteArrayToImage(bytes);
    
                            //If image is not null, display it
                            if(img != null)
                            {
                                //Display returned image
                                pictureBox1.Image = img;
                                Console.WriteLine("Recieved image.");
                            }
                        }                 
                        //Close connection
                        client.Close();
                    }
                }
                catch(SocketException e)
                {
                    Console.WriteLine("SocketException: {0}", e);
                }
                finally
                {
                    //Stop listening for clients
                    server.Stop();
                }
            }
    
            //Convert recieved byte array to an image
            public Image byteArrayToImage(Byte[] byteArrayIn)
            {
                MemoryStream ms = new MemoryStream(byteArrayIn);
                try
                {
                    Image returnImage = Image.FromStream(ms);
                    return returnImage;
                }
                catch (Exception e)
                {
                    Console.WriteLine("{0}", e);
                    //Return a null image if exception is thrown
                    Bitmap returnImage = null;
                    return returnImage;
                }
            }
    My main problem is I'm not sure how to send the image and DateTime together in a single stream.write (if that is even possible).

    Im not asking anyone to write the whole thing for me, I would just like come pointers in the write direction.

    Don't let me down!

    Many thanks in advance,
    bassguru

  2. #2
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Sending DateTime information with image

    I didn't quite go through your code, but, you should be able to define a class that holds both, (call it something like "TimeStampedImage"), and send an instance of that class instead.

  3. #3
    Join Date
    Feb 2010
    Posts
    29

    Re: Sending DateTime information with image

    Thanks for the reply TheGreatCthulhu,

    Code:
        public class timeStampedImage
        {
            public byte[] byteArray;
            public DateTime dateTime;
        }
    
        //Main class class
        {
            //..............................................
            timeStampedClass test = new timeStampedClass();
            test.byteArray = bytes; //Byte array of image to be sent
            test.dateTime = currentTime; //Record of current time to be sent
    
            stream.Write(bytes, 0, bytes.Length);  //<----------Needs changed
        }
    Follwoing your suggestion, how do you suppose I create the instance of the class and use the stream.Write method to send it?

    bassguru

  4. #4
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Sending DateTime information with image

    You can, for example, use the Serialize(Stream, Object) method of the BinaryFormatter class (http://msdn.microsoft.com/en-us/library/c5sbs8z9.aspx).
    The first parameter is the stream to which to serialize, and the second is object to be serialized.

    Note that your timeStampedImage class must be serializable. To do this, just add the [Serializable] attribute before it.

    [Serializable]
    public class timeStampedImage
    {
    // ...
    }

  5. #5
    Join Date
    Feb 2010
    Posts
    29

    Re: Sending DateTime information with image

    Thanks again TheGreatCthulhu

    Your logic seems sound, but I'm still at a loss I'm afraid. This is what I have thus far:

    Code:
        [Serializable]
        public class timeStampedImage
        {
            public byte[] byteArray;
            public DateTime dateTime;
        }
    
        //Main class
        {
                    NetworkStream stream = client.GetStream();
    
                    //Get current time
                    DateTime currentTime = DateTime.Now;
    
                    timeStampedImage test = new timeStampedImage();
                    test.byteArray = bytes;         //Byte array of image to be sent
                    test.dateTime = currentTime;    //Record of current time to be sent
    
                    Serialize(stream, currentTime);
                    
                    stream.Write(bytes, 0, bytes.Length);
        }
    How do you suggest I utilise the serialize method to return a type that contains both byte array (of the image) and the DateTime object?

    Many thanks for your help,
    bassguru

  6. #6
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Sending DateTime information with image

    First, the Serialize(...) method is a member method of the BinaryFormatter class, so you need an instance of it in order to call it.

    Code:
    using System.Runtime.Serialization.Formatters.Binary;  // add this at the top
    
    // ...
    
    BinaryFormatter bFmt = new BinaryFormatter();
    However, my original idea was to call
    Code:
    bFmt.Serialize(stream, dataToSend);
    but, after some testing I realized that this won't work for some reason... Only one byte is sent.
    Not to worry, though. There's a simple solution.

    But first, your code above has an issue - you need to send an instance the timeStampedImage class, the one you named test and then initialized it, and you are trying to send bytes and currentTime individually instead.

    Here's how you can do it, with a little help from the MemoryStream class.
    Code:
    System.IO.MemoryStream memStream = new System.IO.MemoryStream();    
    BinaryFormatter bFmt = new BinaryFormatter();
    bFmt.Serialize(memStream, test);    // basically, this turns your class into an in-memory byte array
    
    byte[] buffer = memStream.GetBuffer();
    
    // Use the NetworkStream to send all the data.
    stream.Write(buffer, 0, buffer.Length);
    Don't forget to call

    memStream.Close();

    when you're done with memStream.


    Note that you'll also need to use a BinaryFormatter instance to deserialize the received data.
    Use the Deserialize() member method - it returns an Object reference, that you can cast into a timeStampedImage, and retrieve your data.
    Last edited by TheGreatCthulhu; March 21st, 2010 at 04:30 PM. Reason: A slight correction...

  7. #7
    Join Date
    Feb 2010
    Posts
    29

    Re: Sending DateTime information with image

    Thanks again for the reply TheGreatCthulhu!

    Your last post really helped to send the instance of the class. However, a problem is occuring that states that "The input stream is not a valid binary format. The starting contents (in bytes) are: 47-49-46-38-39-61-DE-00-BF-00-F7-00-00-00-00-00-80 ...". The code I have thus far is shown below:

    Code:
        [Serializable]
        public class timeStampedImage
        {
            public byte[] byteArray;
            public DateTime dateTime;
        }
    
            //Main class
            public void Connect(String server, Image img)
            {
                try
                {
                //.........................
                    
                    MemoryStream ms = new MemoryStream();
                    img.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
                    bytes = ms.ToArray();
                    DateTime currentTime = DateTime.Now;    //Get current time
    
                    NetworkStream stream = client.GetStream();
    
                    BinaryFormatter bFmt = new BinaryFormatter();   //Create instance of BinaryFormatter class
    
                    timeStampedImage test = new timeStampedImage();
                    test.byteArray = bytes;         //Byte array of image to be sent
                    test.dateTime = currentTime;    //Record of current time to be sent
    
                    System.IO.MemoryStream memStream = new System.IO.MemoryStream();
                    bFmt.Serialize(memStream, test);
    
                    byte[] buffer = memStream.GetBuffer();
    
                    // Use the NetworkStream to send all the data.
                    stream.Write(buffer, 0, buffer.Length);
                    
                    stream.Write(bytes, 0, bytes.Length);
                    Console.WriteLine("Image sent at {0}.", currentTime.TimeOfDay);
                    Console.WriteLine("Sent {0} bytes.", bytes.Length);
    
                    //Close everything
                    memStream.Close();
                    stream.Close();
                    client.Close();
                }
                catch(ArgumentNullException e)
                {
                    Console.WriteLine("ArgumentNullException: {0}", e);
                }
                catch(SocketException e)
                {
                    Console.WriteLine("SocketException: {0}", e);
                }
            }
    The above section is (to the best of my knowledge) the working code. Below is the TcpListener code which the error occurs:

    Code:
            public void Listen()
            {
                TcpListener server = null;
                try
                {
                    string ownPort = txtOwnPort.Text;
                    int port = Convert.ToInt32(ownPort);
    
                    IPAddress localAddr = IPAddress.Parse(txtOwnIP.Text);
    
                    server = new TcpListener(localAddr, port);
    
                    //Start listening for client requests
                    server.Start();
    
                    //Buffer for reading data
                    Byte[] bytes = new Byte[32768];
                    Image img;
                    //Enter the listening loop
                    while(true)
                    {
                        BinaryFormatter bFmt = new BinaryFormatter();
    
                        //Perform a blocking call to accept requests
                        TcpClient client = server.AcceptTcpClient();
    
                        img = null;
    
                        //Get a stream object for reading and writing
                        NetworkStream stream = client.GetStream();
    
                        int i;                    
    
                        //Loop to receive all the data sent by the client
                        while((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            bFmt.Deserialize(stream);  //<--------------ERROR OCCURS HERE
                            DateTime currentTime = DateTime.Now;    //Get current time
                            Console.WriteLine("Recieved {0} bytes at {1}", bytes.Length, currentTime.TimeOfDay);
    
                            //DateTime delayTime = sentTime.Millisecond - currentTime.Millisecond;
      
                            //Convert byte array to image
                            img = byteArrayToImage(bytes);
    
                            //If image is not null, display it
                            if(img != null)
                            {
                                //Display returned image
                                pictureBox1.Image = img;
                                Console.WriteLine("Recieved image.");
                            }
                        }                 
                        //Close connection
                        client.Close();
                    }
                }
                catch(SocketException e)
                {
                    Console.WriteLine("SocketException: {0}", e);
                }
                finally
                {
                    //Stop listening for clients
                    server.Stop();
                }
            }
    Any suggestions? Sorry to keep pestering you, I'm afraid this is all new to me!

    Many thanks in advance,
    bassguru

  8. #8
    Join Date
    Feb 2010
    Posts
    29

    Re: Sending DateTime information with image

    In amendment to my previous post, it would make more sense to deserialize the stream BEFORE the while loop, as shown below:

    Code:
                 
                        bFmt.Deserialize(stream);
    
                        //Loop to receive all the data sent by the client
                        while((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            DateTime currentTime = DateTime.Now;    //Get current time
                            Console.WriteLine("Recieved {0} bytes at {1}", bytes.Length, currentTime.TimeOfDay);
    
                            //DateTime delayTime = sentTime.Millisecond - currentTime.Millisecond;
      
                            //Convert byte array to image
                            img = byteArrayToImage(bytes);
    
                            //If image is not null, display it
                            if(img != null)
                            {
                                //Display returned image
                                pictureBox1.Image = img;
                                Console.WriteLine("Recieved image.");
                            }
                        }
    The question I am asking now is how to cast the returned Object reference into timeStampedImage, and retrieve both the DateTime and Byte[] objects.

    Thanks for all your help,
    bassguru

  9. #9
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Sending DateTime information with image

    Quote Originally Posted by bassguru View Post
    Code:
                    // Use the NetworkStream to send all the data.
                    stream.Write(buffer, 0, buffer.Length);
                    
                    stream.Write(bytes, 0, bytes.Length);
                    Console.WriteLine("Image sent at {0}.", currentTime.TimeOfDay);
                    Console.WriteLine("Sent {0} bytes.", bytes.Length);
    Comment out or delete the emphasized line
    ( stream.Write(bytes, 0, bytes.Length); ).

    Since you're sending all the data via the buffer array, there's no need to send the bytes again.

    I'd also like to point out a few things that I omitted before since I wanted to make sure first at MSDN.
    The GetBuffer() method of the MemoryStream class returns the whole buffer, and not just the data you've written to it. This means that you might end up sending more data than you really need to. There are two ways to go.

    First, you can use the ToArray() method of the same class. This will return a copy of the written data, and only of that data - there won't be any excess bytes. But as it creates a copy, it might not be the best choice in general, since this behavior is undesired with a larger amount of data.

    The second option is to use the GetBuffer() method, but not to send all the bytes. This can be achieved with the Length property of the MemoryStream class.

    To do this, just replace this line
    stream.Write(buffer, 0, buffer.Length);
    with this:
    stream.Write(buffer, 0, (int)memStream.Length);

    (This will send only the data that needs to be sent. Also, note that it has to be type-casted to int since the return type is long.)

    Quote Originally Posted by bassguru View Post
    In amendment to my previous post, it would make more sense to deserialize the stream BEFORE the while loop [...]
    The question I am asking now is how to cast the returned Object reference into timeStampedImage, and retrieve both the DateTime and Byte[] objects.
    Well, you first need to receive all the data that's been sent, and use the Deserialize() method after that. This method, as I've said before, returns your instance of timeStampedImage, but as an object of type Object, since it cannot know what concrete type it should return.

    Also, I don't think you need that inner loop.
    You can learn more about how to use the NetworkStream class here, at the Remarks section.

    So:

    Code:
    object temp = bFmt.Deserialize(stream);
    timeStampedImage myData = temp as timeStampedImage;
    // check if myData != null
    // use myData to get the time and image bytes
    Last edited by TheGreatCthulhu; March 23rd, 2010 at 03:50 PM. Reason: Something to add..

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured