locked
Asynchronous image transfer over TCP/IP socket RRS feed

  • Question

  • Hi every1, 

    I am writing a smal client/server application and in it I want to send an image asynchronous from the client to the server through a TCP socket. I found an example code on the MSDN site, which is actually for sending strings. I tried to adapt this code so that the client sends an image instead of a string. However, there is something wrong on the server side (i guess)...
    The server starts listening, the client starts sending and I become an indication, that the server receives something... but doesn't stop receiving. The else-condition in the function Send_Image() is never reached.

    As far as I understood the Microsoft-code, the data is being sent in parts (every part is with the size of the buffer). That's why the Read_Image() function is called as long as all the data is transfered (that is exactly the if-condition ->  if bytesRead>0 ). I save these data parts (in bytes) in an ArrayList and at the end I convert this ArrayList to a byte array and then to a Bitmap.

    Here is the code. Can anyone help me to find my mistake ... please, I am stuck!!! :(


    The client side:

    public static void StartClient()
            {
                // Connect to a remote device.
                try
                {
                    // Establish the remote endpoint for the socket. 
    // The name of the remote device is "host.domain.com".
                    IPHostEntry ipHostInfo = Dns.Resolve("host.domain.com");
                    IPAddress ipAddress = ipHostInfo.AddressList[0];
                    IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);

                    // Create a TCP/IP socket.
                    Socket client = new Socket(AddressFamily.InterNetwork,
                        SocketType.Stream, ProtocolType.Tcp);

                    // Connect to the remote endpoint.
                    client.BeginConnect(remoteEP,
                        new AsyncCallback(ConnectCallback), client);
                    connectDone.WaitOne();

                    // Send the image to the remote device.
                    string fName = @"\Program Files\Client\image.jpg"; //path to image
                    SendImage(client, new Bitmap(fName));
                    sendDone.WaitOne();

                    // Receive the response from the remote device.
                    Receive(client);
                    receiveDone.WaitOne();

                    // Write the response to the console.
                    Console.WriteLine("Response received : {0}", response);
                    //System.Windows.Forms.MessageBox.Show("Otgovor poluchen");

                    // Release the socket.
                    client.Shutdown(SocketShutdown.Both);
                    client.Close();

                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
    //--------------------------------------------------------------------
            //convet Image to byte[]
            public static byte[] imageToByteArray(Bitmap imageIn)
            {
                MemoryStream ms = new MemoryStream();
                imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                return ms.GetBuffer();
            }
    //--------------------------------------------------------------------
            private static void SendImage(Socket client, Bitmap img)
            {
                // Convert the image to byte data 
                byte[] byteData = imageToByteArray(img);

                // Begin sending the data to the remote device.
                client.BeginSend(byteData, 0, byteData.Length, 0,
                    new AsyncCallback(SendCallback), client);
            }
    //--------------------------------------------------------------------
            private static void SendCallback(IAsyncResult ar)
            {
                try
                {
                    // Retrieve the socket from the state object.
                    Socket client = (Socket)ar.AsyncState;

                    // Complete sending the data to the remote device.
                    int bytesSent = client.EndSend(ar);
                    Console.WriteLine("Sent {0} bytes to server.", bytesSent);  //this msg never shows up!

                    // Signal that all bytes have been sent.
                    sendDone.Set();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }


    The server side: 

         // State object for reading client data asynchronously
    public class StateObject {
        // Client  socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 1024*10;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];  
    // Received image bytes
        public ArrayList imageBytes = new ArrayList();
    }
    //----------------------------------------------------------------------
        public static void StartListening() {
            // Data buffer for incoming data.
            byte[] bytes = new Byte[1024];

            // Establish the local endpoint for the socket.
            // The DNS name of the computer running the listener is "server.domain.com".
            IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
            IPAddress ipAddress = ipHostInfo.AddressList[0];
            IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);

            // Create a TCP/IP socket.
            Socket listener = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp );

            // Bind the socket to the local endpoint and listen for incoming connections.
            try {
                listener.Bind(localEndPoint);
                listener.Listen(100);

                while (true) {
                    // Set the event to nonsignaled state.
                    allDone.Reset();

                    // Start an asynchronous socket to listen for connections.
                    System.Windows.Forms.MessageBox.Show("Waiting for a connection...");
                    listener.BeginAccept( 
                        new AsyncCallback(AcceptCallback),
                        listener );

                    // Wait until a connection is made before continuing.
                    allDone.WaitOne();
                }

            } catch (Exception e) {
                Console.WriteLine(e.ToString());
                System.Windows.Forms.MessageBox.Show(e.ToString());
            }

            System.Windows.Forms.MessageBox.Show("\nPress ENTER to continue...");
            Console.Read();
            
        }
    //----------------------------------------------------------------------
        public static void AcceptCallback(IAsyncResult ar) {
            // Signal the main thread to continue.
            allDone.Set();

            // Get the socket that handles the client request.
            Socket listener = (Socket) ar.AsyncState;
            Socket handler = listener.EndAccept(ar);

            // Create the state object.
            StateObject state = new StateObject();
            state.workSocket = handler;
            handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(Read_Image), state);
    }
    //--------------------------------------------------------
        public static void Read_Image(IAsyncResult ar)
        {
            StateObject so = (StateObject)ar.AsyncState;
            Socket s = so.workSocket;

            int read = s.EndReceive(ar);

            if (read > 0)
            {
                //so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read));
                foreach (byte el in so.buffer) 
                {
                    so.imageBytes.Add(el);
                }
                s.BeginReceive(so.buffer, 0, StateObject.BufferSize, 0,new AsyncCallback(Read_Image), so);
                System.Windows.Forms.MessageBox.Show("read > 0, call Read_Image recursively");
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("Else case");
                if (so.imageBytes.Count > 0)
                {
                    //All of the data has been read, so displays it to the console
                    byte[] imageBytesArray = new byte[so.imageBytes.Count];
                    so.imageBytes.CopyTo(imageBytesArray);
                    myForm.pictureBox1.Image = ImgConverter.byteArrayToImage(imageBytesArray);
                    //Send(s, "<EOF>");
                    //System.Windows.Forms.MessageBox.Show("Sent!");
                }
                System.Windows.Forms.MessageBox.Show("Receive done!");
                Send(s, "<EOF>");  //this sends a msg to the client and closes the socket connection. I didn't paste the function
                s.Close();
            }
        }




    Thanks in advance!

    Cheers,
    Vasil

    Monday, September 8, 2008 10:00 PM

Answers

  • Vasil,

    Consider the following piece of your server...

            if (read > 0)
            {
                //so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read));
                foreach (byte el in so.buffer
                {
                    so.imageBytes.Add(el);
                }
                s.BeginReceive(so.buffer, 0, StateObject.BufferSize, 0,new AsyncCallback(Read_Image), so);
                System.Windows.Forms.MessageBox.Show("read > 0, call Read_Image recursively");
            }

    "read" is the size that was read, "so.buffer" is the size of the buffer and the maximum size of any single read.  "read" can be any size up to the size of the request.  So, by your logic, if "read" is 10 bytes, your foreach loop will copy 10,000 bytes.  Notice how the original code used "read" for the size of the GetString() and not so.buffer.Length.

    I don't know if this is your problem, because even if it is just this, your code would eventually return.  How big is the file?  Consider putting in some debug statements to show the value of "read".

    Les Potter, Xalnix Corporation, Yet Another C# Blog
    • Marked as answer by keksy Sunday, May 9, 2010 8:55 PM
    Monday, September 8, 2008 11:32 PM