局域網內【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的話延遲太高導致客戶端各種無響應。考慮過室友提出的緩衝池。但只是能解決無響應的問題。畫面還是會卡頓。求不特別依賴網速的其他實現方法。

       適應屏幕是手動調大小的。。心好累。

       沒寫註釋。感覺看官老爺們看代碼會很憂桑。。。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章