首页 > 解决方案 > How to continuously send a network stream in c#

问题描述

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

标签: c#.netnetworkingservertcp

解决方案


你的问题是

Image returnImage = Image.FromStream(nNetStream);

直到流结束才会完成执行,因此不会让窗口初始化运行。你需要的是

  1. 在单独的线程中运行连接部分,因此它不会阻塞 UI 线程
  2. 区分图像帧并一一放入图片框的方法

要实现第一点,您可以使用System.Threading.Task. 您需要记住,您不能直接从单独的线程访问 UI,因此您需要在图片框上使用 Invoke()。为了实现第二个,我会设计一些简单的通信协议并复制网络流数据以分离MemoryStream以从中创建图像。

例如,总是发送一个Int32指示要读取的字节数(即发送的图像的大小),然后发送包含图像的 n 个字节。然后您可以从网络流中读取单个 int,确定要复制到的数据量,MemoryStream然后复制该量以创建 Image。


推荐阅读