How to continuously send a network stream in c#

Viewed 299

I am trying to understand tcp server/client communication for school.

What I am trying to do is to send a screenshot of the screen to the client.

All is working fine, but now I want it to make it send over and over again (pretty much a screenshare) and I can't find a solution myself.

Here is the code:

Server

class Program
{

    static void Main(string[] args)
    {
        Run();
    }

    private static void Run()
    {
        StartClientAsync();
    }

    public static async System.Threading.Tasks.Task StartClientAsync()
    {
        try
        {
            IPAddress ipAddress = Dns.Resolve("localhost").AddressList[0];
            TcpListener server = new TcpListener(ipAddress, 9500);
            server.Start();
            Console.WriteLine("Waiting for client to connect...");

            while (true)
            {
                if (server.Pending())
                {
                    Bitmap tImage;
                    byte[] bStream;

                    while (true)
                    {
                        using (var client = await server.AcceptTcpClientAsync())
                        {
                            Console.WriteLine("Connected");
                            NetworkStream nStream = client.GetStream();

                            try
                            {
                                tImage = Screenshot();
                                bStream = ImageToByte(tImage);
                                nStream.Write(bStream, 0, bStream.Length);
                                Console.WriteLine("Sent Image");
                            }
                            catch (SocketException e1)
                            {
                                Console.WriteLine("SocketException: " + e1);
                            }

                        }
                        Console.WriteLine("Disconnected");
                    }
                }
            }
        }

        catch (SocketException e1)
        {
            Console.WriteLine("SocketException: " + e1);
        }
    }

    static byte[] ImageToByte(Image iImage)
    {
        MemoryStream mMemoryStream = new MemoryStream();
        iImage.Save(mMemoryStream, System.Drawing.Imaging.ImageFormat.Png);
        return mMemoryStream.ToArray();
    }

    private static Bitmap Screenshot()
    {
        var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
            Screen.PrimaryScreen.Bounds.Height,
            PixelFormat.Format32bppArgb);

        // Create a graphics object from the bitmap.
        var gfxScreenshot = Graphics.FromImage(bmpScreenshot);

        // Take the screenshot from the upper left corner to the right bottom corner.
        gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
            Screen.PrimaryScreen.Bounds.Y,
            0,
            0,
            Screen.PrimaryScreen.Bounds.Size,
            CopyPixelOperation.SourceCopy);

        return bmpScreenshot;
    }
}

Client

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Start();
    }

    public void Start()
    {
        IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
        using (TcpClient client = new TcpClient())
        {
            client.Connect(ipAddress, 9500);
            Log("Connected...");

            Thread.Sleep(500);
            NetworkStream nNetStream = client.GetStream();
            Image returnImage = Image.FromStream(nNetStream);
            pictureBox1.Image = returnImage;
        }
    }

    private void Log(string text)
    {
        if (ControlInvokeRequired(textBox1, () => Log(text))) return;
        Console.WriteLine(text);
        textBox1.AppendText(text);
        textBox1.AppendText(Environment.NewLine);
    }

    public bool ControlInvokeRequired(Control c, Action a)
    {
        if (c.InvokeRequired) c.Invoke(new MethodInvoker(delegate { a(); }));
        else return false;

        return true;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        pictureBox1.Image.Save(DateTime.Now.Ticks.ToString("D19") + ".png", ImageFormat.Png);
    }
}

I tried using a additional while loop, but when I execute it, the client won't start the form, until I stop the server manually.

The Image should be updated in the picturebox, every time a new image was sent.

Thanks

1 Answers

Your problem is that

Image returnImage = Image.FromStream(nNetStream);

won't finish executing until the end of stream, thus not letting the window initialization to run. What you need is

  1. Running the connection part in separate thread, so it won't block the UI thread
  2. Method to distinguish between image frames and getting them one by one to put into picturebox

To achieve first point you might use System.Threading.Task. You need to remember, that you can't access UI directly from separate thread, so you'll need to use Invoke() on picturebox. To achieve 2nd one I'd design some simple comms protocol and copy network stream data to separate MemoryStream to create image out of it.

For example, always send one Int32 indicating number of bytes to read (i.e. size of the image sent), then n bytes containing image. Then you can go with reading single int from network stream, figuring out the amount of data to copy to MemoryStream and then copy that amount to create Image.

Related