locked
Image Transfer Problem with Sockets RRS feed

  • Question

  • Here is my problem. I am trying to send an image streaming from my camera on a local machine to a host computer. It's a Canon Camera  and I'm using their SDK. I can get the image off the camera as a Byte Array. I have viewed it locally and all is well. When I send it however I loss half the image or more. I have no Idea why. I've played with it several different ways and can't understand why the image is corrupt

    Here is my Server Code:

    //first, because the size of the image isn't fixed I send the Size of the image to the remote PC
     public void SendSize(byte[] imageContent)
            {

                TcpClient client = new TcpClient();

                IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);

                client.Connect(serverEndPoint);

                NetworkStream clientStream = client.GetStream();

                int size = imageContent.Length;
                String X = size.ToString();

                byte[] buffer = BitConverter.GetBytes(size);
                Console.Write("Sending Size :" + size);
                clientStream.Write(buffer, 0, buffer.Length);
                clientStream.Flush();
                client.Close();

    // Next I send the Image

    public void SendServer(byte[] imageContent)
            {

                TcpClient client = new TcpClient();

                //IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.4.37"), 3000);
                IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
                client.Connect(serverEndPoint);

                NetworkStream clientStream = client.GetStream();
                ImageConverter enc = new ImageConverter();


                clientStream.Write(imageContent, 0, imageContent.Length);
                clientStream.Flush();
            }

    // Here is the remote Comps Code
    //First I receive the Size

    private void SetSize(object client)
            {
                message = new byte[4096];
                tcpClient = (TcpClient)client;
                NetworkStream clientStream = tcpClient.GetStream();
                int bytesRead = clientStream.Read(message, 0, 4096);

                string stringData = BitConverter.ToInt32(message, 0).ToString();
                sz = Convert.ToInt32(stringData);
                //Thread.Sleep(10);
                //message = new byte[sz];
                Console.WriteLine("Received Size " + sz);
               
                tcpClient.Close();

            }

    //Then I receive the Image

    private void GetImage(object client)
            {
                MemoryStream streamImage = null;
                Console.WriteLine("Size is Still " + sz);
                message = new byte[sz];
                tcpClient = (TcpClient)client;
                NetworkStream clientStream = tcpClient.GetStream();

                byte[] Fini = new byte[sz];
                int bytesRead = 0;
                /*
                while (bytesRead < sz - 1)
                {
                    bytesRead += clientStream.Read(message, 0, sz);
                   
                }
                 * */

                for (int i = 0; i < sz-1; i++)
                {
                    try
                    {
                        Fini[i] = (byte)clientStream.ReadByte();
                       
                    }
                    catch
                    {
                        Console.WriteLine("Connection Lost");
                        break;
                    }
                }

                Console.WriteLine("BytesRead is " + bytesRead);

                try
                {
                    streamImage = new MemoryStream(Fini, 0, Fini.Length);
                    streamImage.Write(Fini, 0, sz);
                    Image X = Image.FromStream(streamImage);
                    streamImage.Flush();
                    streamImage.Close();
                    pictureBox1.Image = X;
                }
                catch
                {
                    Console.WriteLine("Frame Lost");
                }

               
                /*
                streamImage = new MemoryStream(message,0,message.Length);
                streamImage.Write(message, 0, sz);
                Bitmap Y = (Bitmap)Bitmap.FromStream(streamImage);
                */
               

                tcpClient.Close();

            }
    Thanks for any help in advance

    P.S. I'm also getting some Errors:
    A first chance exception of type 'System.IO.IOException' occurred in System.dll
    A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll

    Not sure how to fix this

    Monday, August 17, 2009 2:23 PM

Answers

  • A couple of things that look wrong.  You are not closing the stream in SendServer.  You are writing the size to the memory stream in GetImage().  The last one should be enough to get the image decoder to throw a fit.  Also be sure that the imageContent array was written by Image.Save(), just the bitmap bits isn't good enough.

    Hans Passant.
    • Proposed as answer by Harry Zhu Monday, August 24, 2009 7:55 AM
    • Marked as answer by Harry Zhu Tuesday, August 25, 2009 9:06 AM
    Monday, August 17, 2009 4:22 PM
  • You're also discarding the result from Socket.Read when reading the length. This will result in an obscure bug.

    For example code that shows how to do length prefixing, see: http://nitoprograms.blogspot.com/2009/04/sample-code-length-prefix-message.html

           -Steve
    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ
    MSBuild user? Try out the DynamicExecute task in the MSBuild Extension Pack source; it's currently in Beta so get your comments in!
    I will be at the Grand Rapids BarCamp 4 unconference - come on by, fellow Michiganders!
    • Proposed as answer by Harry Zhu Monday, August 24, 2009 7:55 AM
    • Marked as answer by Harry Zhu Tuesday, August 25, 2009 9:06 AM
    Monday, August 17, 2009 5:42 PM
  • Ok, Try change
        while (bytesRead < sz - 1)
                {
                    bytesRead += clientStream.Read(Message, bytesRead, sz - bytesRead);

                }

    to
        while (bytesRead < sz - 1)
                {
                    bytesRead += clientStream.Read(Fini, bytesRead, sz - bytesRead);

                }

    I didnt see that the code is using Fini rather than Message
    • Proposed as answer by Harry Zhu Monday, August 24, 2009 7:55 AM
    • Marked as answer by Harry Zhu Tuesday, August 25, 2009 9:06 AM
    Monday, August 17, 2009 8:51 PM
  • public void SendData(byte[] data)
    {
        using (TcpClient client = new TcpClient())
        {
            IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
            client.Connect(serverEndPoint);
            using (NetworkStream clientStream = client.GetStream())
            {
                int size = data.Length;
                byte[] sizeBuffer = BitConverter.GetBytes(size);
                clientStream.Write(sizeBuffer, 0, sizeBuffer.Length);
                clientStream.Write(data, 0, size);
            }
        }
    }
    
    public void SendImage(Image image, ImageFormat format)
    {
        byte[] data;
        using (MemoryStream stream = new MemoryStream())
        {
            image.Save(stream, format);
    
            data = new byte[16 + stream.Length];
            Array.Copy(format.Guid.ToByteArray(), data, 16);
            Array.Copy(stream.ToArray(), 0, data, 16, stream.Length);
        }
    
        SendData(data);
    }
    
    private byte[] ReceiveData(TcpClient client)
    {
        using (NetworkStream clientStream = client.GetStream())
        {
            byte[] sizeBuffer = new byte[4];
            int sizeBufferBytesRead = 0;
            while (sizeBufferBytesRead != 4)
            {
                sizeBufferBytesRead += clientStream.Read(sizeBuffer, sizeBufferBytesRead, 4 - sizeBufferBytesRead);
            }
    
            int size = BitConverter.ToInt32(sizeBuffer, 0);
            byte[] dataBuffer = new byte[size];
            int dataBufferBytesRead = 0;
            while (dataBufferBytesRead != size)
            {
                dataBufferBytesRead += clientStream.Read(dataBuffer, dataBufferBytesRead, size = dataBufferBytesRead);
            }
    
            return dataBuffer;
        }
    }
    
    private Image ReceiveImage(TcpClient client, out ImageFormat format)
    {
        byte[] data = ReceiveData(client);
        Trace.Assert(data.Length > 16);
    
        format = new ImageFormat(new Guid(data.Take(16).ToArray()));
    
        // Note: do *not* use a "using" statement here; Image.FromStream requires that the stream remain valid.
        MemoryStream stream = new MemoryStream(data, 16, data.Length - 16);
        return Image.FromStream(stream);
    }
    


           -Steve
    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ
    MSBuild user? Try out the DynamicExecute task in the MSBuild Extension Pack source; it's currently in Beta so get your comments in!
    I will be at the Grand Rapids BarCamp 4 unconference - come on by, fellow Michiganders!
    • Proposed as answer by Harry Zhu Monday, August 24, 2009 7:55 AM
    • Marked as answer by Harry Zhu Tuesday, August 25, 2009 9:06 AM
    Tuesday, August 18, 2009 1:10 PM

All replies

  • Hi
    Remove

     for (int i = 0; i < sz-1; i++)
                {
                    try
                    {
                        Fini[i] = (byte)clientStream.ReadByte();
                        
                    }
                    catch
                    {
                        Console.WriteLine("Connection Lost");
                        break;
                    }
                }

    and

    change
    while (bytesRead < sz - 1)
                {
                    bytesRead += clientStream.Read(message, 0, sz);
                    
                }

    to
    while (bytesRead < sz - 1)
                {
                    bytesRead += clientStream.Read(message, bytesRead, sz - bytesRead);
                    
                }

    Monday, August 17, 2009 3:08 PM
  • That works.... but now I get "Parameter is Not valid" from:

    X = Image.FromStream(streamImage);

    which is totally ridiculous to me but I haven't found a solution to this problem.
    Monday, August 17, 2009 3:17 PM
  • try
    StreamImage.Seek(0, SeekOrigin.Begin); 
    before that line
    Monday, August 17, 2009 3:21 PM
  • No dice. Still same Exception.
    Monday, August 17, 2009 3:30 PM
  • You probably dont need to even do the write
    You can just say

      streamImage = new MemoryStream(Fini, 0, Fini.Length);
                    Image X = Image.FromStream(streamImage);
                    streamImage.Close();
                    pictureBox1.Image = X;
    Monday, August 17, 2009 3:35 PM
  • Tried that too. Still Same Problem. I have found that, that particular error usually occurs when the Data is invalid picture format but I have tested if before and after it is sent locally and it works. So I don't know what the problem is.
    Monday, August 17, 2009 3:42 PM
  • A couple of things that look wrong.  You are not closing the stream in SendServer.  You are writing the size to the memory stream in GetImage().  The last one should be enough to get the image decoder to throw a fit.  Also be sure that the imageContent array was written by Image.Save(), just the bitmap bits isn't good enough.

    Hans Passant.
    • Proposed as answer by Harry Zhu Monday, August 24, 2009 7:55 AM
    • Marked as answer by Harry Zhu Tuesday, August 25, 2009 9:06 AM
    Monday, August 17, 2009 4:22 PM
  • You're also discarding the result from Socket.Read when reading the length. This will result in an obscure bug.

    For example code that shows how to do length prefixing, see: http://nitoprograms.blogspot.com/2009/04/sample-code-length-prefix-message.html

           -Steve
    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ
    MSBuild user? Try out the DynamicExecute task in the MSBuild Extension Pack source; it's currently in Beta so get your comments in!
    I will be at the Grand Rapids BarCamp 4 unconference - come on by, fellow Michiganders!
    • Proposed as answer by Harry Zhu Monday, August 24, 2009 7:55 AM
    • Marked as answer by Harry Zhu Tuesday, August 25, 2009 9:06 AM
    Monday, August 17, 2009 5:42 PM
  • Ok, Try change
        while (bytesRead < sz - 1)
                {
                    bytesRead += clientStream.Read(Message, bytesRead, sz - bytesRead);

                }

    to
        while (bytesRead < sz - 1)
                {
                    bytesRead += clientStream.Read(Fini, bytesRead, sz - bytesRead);

                }

    I didnt see that the code is using Fini rather than Message
    • Proposed as answer by Harry Zhu Monday, August 24, 2009 7:55 AM
    • Marked as answer by Harry Zhu Tuesday, August 25, 2009 9:06 AM
    Monday, August 17, 2009 8:51 PM
  • public void SendData(byte[] data)
    {
        using (TcpClient client = new TcpClient())
        {
            IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
            client.Connect(serverEndPoint);
            using (NetworkStream clientStream = client.GetStream())
            {
                int size = data.Length;
                byte[] sizeBuffer = BitConverter.GetBytes(size);
                clientStream.Write(sizeBuffer, 0, sizeBuffer.Length);
                clientStream.Write(data, 0, size);
            }
        }
    }
    
    public void SendImage(Image image, ImageFormat format)
    {
        byte[] data;
        using (MemoryStream stream = new MemoryStream())
        {
            image.Save(stream, format);
    
            data = new byte[16 + stream.Length];
            Array.Copy(format.Guid.ToByteArray(), data, 16);
            Array.Copy(stream.ToArray(), 0, data, 16, stream.Length);
        }
    
        SendData(data);
    }
    
    private byte[] ReceiveData(TcpClient client)
    {
        using (NetworkStream clientStream = client.GetStream())
        {
            byte[] sizeBuffer = new byte[4];
            int sizeBufferBytesRead = 0;
            while (sizeBufferBytesRead != 4)
            {
                sizeBufferBytesRead += clientStream.Read(sizeBuffer, sizeBufferBytesRead, 4 - sizeBufferBytesRead);
            }
    
            int size = BitConverter.ToInt32(sizeBuffer, 0);
            byte[] dataBuffer = new byte[size];
            int dataBufferBytesRead = 0;
            while (dataBufferBytesRead != size)
            {
                dataBufferBytesRead += clientStream.Read(dataBuffer, dataBufferBytesRead, size = dataBufferBytesRead);
            }
    
            return dataBuffer;
        }
    }
    
    private Image ReceiveImage(TcpClient client, out ImageFormat format)
    {
        byte[] data = ReceiveData(client);
        Trace.Assert(data.Length > 16);
    
        format = new ImageFormat(new Guid(data.Take(16).ToArray()));
    
        // Note: do *not* use a "using" statement here; Image.FromStream requires that the stream remain valid.
        MemoryStream stream = new MemoryStream(data, 16, data.Length - 16);
        return Image.FromStream(stream);
    }
    


           -Steve
    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ
    MSBuild user? Try out the DynamicExecute task in the MSBuild Extension Pack source; it's currently in Beta so get your comments in!
    I will be at the Grand Rapids BarCamp 4 unconference - come on by, fellow Michiganders!
    • Proposed as answer by Harry Zhu Monday, August 24, 2009 7:55 AM
    • Marked as answer by Harry Zhu Tuesday, August 25, 2009 9:06 AM
    Tuesday, August 18, 2009 1:10 PM