局域网内【1 to N】的屏幕共享_基于WPF。【不完善】

由于种种原因刷了两个晚上写了这个东西。必须吐槽一下WPF和WinForm的库不一样好麻烦。

BitmapImage、BitmapSource和Bitmap这三个东西弄的我好烦躁。

第一次用异步Socket。写的时候还不是很懂好在Socket部分一次成不用Debug。写完这篇再慢慢回味一下代码。

之前写Shuide的时候服务器总是在连接第二个客户端的时候死掉。当时调了好久没调出来现在来看换成异步应该就阔以了。。。写完这篇就去重写Shuide的后台了。



服务器端的代码。。感觉这次的代码没什么核心技术。就干脆全贴上来了。。。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Interop;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;


namespace ScreenServer
{

    public partial class MainWindow : Window
    {

        private Socket serverSocket;
        private IPEndPoint serverIEP;
        private BitmapImage imgBuffer;
        private delegate void SetImageCallBack(BitmapImage bitImage);
        SetImageCallBack setImageCallBack;
        private delegate void SetTextblockStateCallBack(String Str);
        SetTextblockStateCallBack setTextblockStateCallBack;
        private int Time;

        public MainWindow()
        {

            InitializeComponent();

            setImageCallBack = new SetImageCallBack(SetImage);
            setTextblockStateCallBack = new SetTextblockStateCallBack(SetTextblockState);
            Time = 50;

        }

        private void buttonStart_Click(object sender, RoutedEventArgs e)
        {

            textblockState.Dispatcher.Invoke(setTextblockStateCallBack, "开始监听.........");
            buttonStart.IsEnabled = false;
            int port = 51888;
            if (textboxTime.Text != "" && textboxTime.Text != null)
            {
                Time = int.Parse(textboxTime.Text);
            }

            try
            {
                
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                serverIEP = new IPEndPoint(IPAddress.Any, port);
                serverSocket.Bind(serverIEP);
                serverSocket.Listen(20);

                Thread threadAccept = new Thread(new ThreadStart(Accept));
                threadAccept.IsBackground = true;
                threadAccept.Start();


            }
            catch
            {

            }

        }

        private void Accept()
        {

            while(true)
            {

                Socket client = serverSocket.Accept();

                textblockState.Dispatcher.Invoke(setTextblockStateCallBack, "用户 " + ((IPEndPoint)client.RemoteEndPoint).Address.ToString() + " 已登录!");

                Thread threadSend = new Thread(new ParameterizedThreadStart(Send));
                threadSend.IsBackground = true;
                threadSend.Start(client);

            }

        }

        private void Send(Object Obj)
        {
            try
            {

                Socket client = (Socket)Obj;
                Bitmap bitmap = GetBitmapFromScreen();
                Byte[] byteBuffer = new Byte[1048567];
                byteBuffer = BitmapToByte(bitmap);

                if (client.Connected)
                {
                    client.BeginSend(byteBuffer, 0, byteBuffer.Length, SocketFlags.None, new AsyncCallback(SendCallBack), client);
                }
            }
            catch
            {

            }

        }

        private void SendCallBack(IAsyncResult AR)
        {
            try
            {

                Thread.Sleep(Time);

                Socket client = (Socket)AR.AsyncState;
                Bitmap bitmap = GetBitmapFromScreen();
                Byte[] byteBuffer = new Byte[1048567];
                byteBuffer = BitmapToByte(bitmap);

                if (client.Connected)
                {
                    client.BeginSend(byteBuffer, 0, byteBuffer.Length, SocketFlags.None, new AsyncCallback(SendCallBack), client);
                }

            }
            catch
            {
                textblockState.Dispatcher.Invoke(setTextblockStateCallBack, "1名用户退出登录!");
            }

        }

        private Bitmap GetBitmapFromScreen()
        {

            System.Drawing.Rectangle rc = SystemInformation.VirtualScreen;
            var bitmap = new Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CopyFromScreen(rc.X, rc.Y, 0, 0, rc.Size, System.Drawing.CopyPixelOperation.SourceCopy);
            }

            return bitmap;

        }

        private Byte[] BitmapToByte(Bitmap bitmap)
        {

            MemoryStream stream = new MemoryStream();
            bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
            Byte[] buffer = new Byte[1048567];
            stream.Seek(0, SeekOrigin.Begin);
            stream.Read(buffer, 0, Convert.ToInt32(stream.Length));
            return buffer;

        }

        private void SetTextblockState(String Str)
        {
            textblockState.Text = Str;
        }

        private void buttonRefresh_Click(object sender, RoutedEventArgs e)
        {

            Time = int.Parse(textboxTime.Text);

        }

    }

}


客户端的代码。。。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Drawing;
using System.Threading;

namespace ScreenClient
{

    public partial class MainWindow : Window
    {

        private IPAddress remoteIPA;
        private IPEndPoint remoteIEP;
        private int port;
        private Socket server;
        private Byte[] byteBuffer;
        private BitmapImage imgBuffer;
        private delegate void SetImageCallBack(BitmapImage bitmapImage);
        SetImageCallBack setImageCallBack;

        public MainWindow()
        {
            InitializeComponent();
            setImageCallBack = new SetImageCallBack(SetImage);
        }

        private void Go_Click(object sender, RoutedEventArgs e)
        {



            remoteIPA = IPAddress.Parse(textboxIP.Text);
            port = 51888;
            remoteIEP = new IPEndPoint(remoteIPA, port);
            byteBuffer = new Byte[1048576];
            imgBuffer = new BitmapImage();
            server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                server.Connect(remoteIEP);

                if (server.Connected)
                {
                    Thread threadReceive = new Thread(new ThreadStart(Receive));
                    threadReceive.IsBackground = true;
                    threadReceive.Start();
                }

            }
            catch
            {

            }

        }

        private void Receive()
        {

            while (true)
            {

                try
                {
                    server.Receive(byteBuffer);
                    try
                    {
                        imgBuffer = new BitmapImage();
                        imgBuffer.BeginInit();
                        imgBuffer.StreamSource = new MemoryStream(byteBuffer);
                        imgBuffer.EndInit();
                        imgBuffer.Freeze();
                    }
                    catch
                    {
                        imgBuffer = null;
                    }

                }
                catch
                {
                    System.Windows.MessageBox.Show("与服务器断开连接!");
                    this.Close();
                }

                imageScreen.Dispatcher.BeginInvoke(setImageCallBack, imgBuffer);
            }

        }

        private void SetImage(BitmapImage bitmapImage)
        {

            imageScreen.Source = bitmapImage;

        }

    }
}


大概实现方法就是截图存成Bitmap。然后转成Byte。传到Client。再转回BitmapImage。然后贴到客户端的Image控件上。。。

不得不吐槽。BitmapImage和Bitmap完全就是一样的东西还非要在不同的库里面起不同的名字。好烦躁。。。


目前的问题:

       网速硬伤。使用Wifi的话延迟太高导致客户端各种无响应。考虑过室友提出的缓冲池。但只是能解决无响应的问题。画面还是会卡顿。求不特别依赖网速的其他实现方法。

       适应屏幕是手动调大小的。。心好累。

       没写注释。感觉看官老爷们看代码会很忧桑。。。


你可能感兴趣的:(C#,WPF)