简体   繁体   中英

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)

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.

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, eg from a System.IO.FileStream .

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM