Search code examples
c#socketstcpwebcampacket

TCP Packet Sending Error


I'm making a webcam app that sends and receives small images. I have made it be able to send and receive, I tested on 127.0.0.1 and it worked fine, but now I'm using my own external IP address and it seems to send one image, receive one, then mess up, I get some sort of massive integer value in the image size, a minus value which leads it to crash, I think maybe the receive and send are running on their own, and are going out of sync somehow. I put a 1000ms delay before sending out each image and it was slow but working, as soon as I take the delay out, it messes up.

Here is the code :

    // This sends.
    private void NewFrameReceived(object sender, NewFrameEventArgs e)
    {
        Bitmap img = (Bitmap)e.Frame.Clone();

        byte[] imgBytes = EncodeToJpeg(img, 25).ToArray();
        if (_tcpOut.Connected)
        {
            NetworkStream ns = _tcpOut.GetStream();
            if (ns.CanWrite)
            {
                System.Threading.Thread.Sleep(500);
                ns.Write(BitConverter.GetBytes(imgBytes.Length), 0, 4);
                ns.Write(imgBytes, 0, imgBytes.Length);
            }
        }
    }

    // This receives.
    private void listeningThread_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        // start listening for connections
        _tcpIn = new TcpListener(IPAddress.Any, 54321);
        _tcpIn.Start();

        TcpClient _inClient = _tcpIn.AcceptTcpClient();
        while (true)
        {
            NetworkStream ns = _inClient.GetStream();
            if (ns.CanRead && ns.DataAvailable)
            {
                Byte[] imgSizeBytes = new Byte[4];
                ns.Read(imgSizeBytes, 0, 4);
                int imgSize = BitConverter.ToInt32(imgSizeBytes, 0);

                Byte[] imgBytes = new Byte[imgSize];  <-- ERROR, GET CRAZY LARGE VALUE
                ns.Read(imgBytes, 0, imgSize);

                MemoryStream ms = new MemoryStream(imgBytes);
                Image img = Image.FromStream(ms);

                picVideo.Image = img;
            }
        }
    }

Solution

  • Read doesn't necessarily read as many bytes as you ask for, just as many happen to be currently available -- you should actually check the return value to see how many it read. The documentation might help give you a better understanding.

    You should add logic to keep reading until all of the image bytes have been read. A pseudo-code example:

    total_bytes_read = 0;
    while (total_bytes_read != total_bytes_needed)
    {
        bytes_left_to_read = total_bytes_needed - total_bytes_read;
        total_bytes_read += read(buffer, total_bytes_read, bytes_left_to_read);
    }