user2194241
user2194241

Reputation: 21

Sending jpg using tcp socket

I have a few problem to send jpg data using a socket.

Sender side:

Socket client_s = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);
IPEndPoint serverEP = new IPEndPoint(IPAddress.Loopback, 4567);
client_s.Connect(serverEP);
NetworkStream stream = new NetworkStream(client_s);
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);

Receiver side:

clientSocket = listenSocket.Accept();
NetworkStream s = new NetworkStream(clientSocket); 
Bitmap slice_bmp = new Bitmap(s);
Graphics g = this.CreateGraphics();
g.DrawImage(slice_bmp,0,0);

When I execute the above, Bitmap slice_bmp = new Bitmap(s); is blocked until closing sender's socket. After sender's socket is closed, an image is drawn normally. I want to know why that operation is blocked?

Also, is it right using instance of Networkstream as argument of constructor of Bitmap? (My code is based on inheritance)

Upvotes: 0

Views: 1751

Answers (3)

Nikola Davidovic
Nikola Davidovic

Reputation: 8656

First of all, I would suggest you to use Flush() method of the NetworkStream to be sure that all the data has been sent.

        Socket client_s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint serverEP = new IPEndPoint(IPAddress.Loopback, 4567);
        client_s.Connect(serverEP);
        NetworkStream stream = new NetworkStream(client_s);
        bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
        stream.Flush(); //flush everything

On the receiver's side, you should first read all the bytes of the image into a byte array. From that byte array you could construct the MemoryStream and than Bitmap from that stream.

        clientSocket = listenSocket.Accept();
        NetworkStream s = new NetworkStream(clientSocket);
        int bytesRead = 0;
        int howMany = 0;
        byte [] byteBuffer = new byte[100000];
        do
        {
            howMany = s.Read(byteBuffer, bytesRead, 10000);
            bytesRead += howMany;
            if(bytesRead>=byteBuffer.Length)
                byteBuffer = ResizeByteArray(byteBuffer);
        }
        while (howMany > 0 && s.DataAvailable);
        MemoryStream ms = new MemoryStream(byteBuffer);
        Bitmap slice_bmp = new Bitmap(ms);
        Graphics g = this.CreateGraphics();
        g.DrawImage(slice_bmp, 0, 0);
        g.Dispose();

If the image is larger from the capacity of the instantiated byte array, then you need to resize it. You could use this helper method:

    private byte[] ResizeByteArray(byte[] arr)
    {
        byte[] newArr = new byte[arr.Length * 2];
        Array.Copy(arr, newArr, arr.Length);
        return newArr;
    }

And as a side note, always call Dispose on Graphics object that you create manually (like in this case). I checked the code and it works.

Upvotes: 2

Jack Gajanan
Jack Gajanan

Reputation: 1670

This is because bitmap class waits for transmission to end:

First receive byte data buffer separately, then create memory stream from it and then create bitmap.

Upvotes: 0

bash.d
bash.d

Reputation: 13207

It appears you are working on a single threaded-application, or at least on the UI-thread of a multi-threaded-application. The blocking appears because your bitmap object is waiting for its construction to be complete. And as it takes a while to read from a stream over a network, your program will not continue until your bitmap-object is fully created.

If you wanted your program to go on, you would need to create a thread and have it read from the stream and create the bitmap. When the bitmap is ready you could fire an event and act appropriately.

As NetworkStream is a subclass of System.IO.Stream it is perfectly fine! You can use any System.IO.Stream to create an object that requires a stream. The only result is, as you experienced, it might take a little longer than creating the image, e.g. from a System.IO.FileStream.

Have a look at MSDN most of the stuff is well described.

Upvotes: 0

Related Questions