局域网控制(一)界面传输

 突然想起来用API结合C#的网络编程来做点东西!

    结合Socket通信及Windows API,通过发送或接收数据来执行相应的操作,可以实现对某台计算机操作。下面就一个简单的局域网控制实例来说明这一过程,具体可以通过一个客户端和一个控制端来实现,客户端主要运行在客户计算机上(即被控制的计算机上),控制端运行在服务器主机上。

无论是对于客户端还是控制端,都必须包含发送数据至目标计算机上和接受目标计算机上的数据这两部分,这个过程主要通过Socket通信来实现。至于具体发送什么数据以及如何将这些数据来转换成计算机指令,则主要是API的事情了。

首先新建一个客户端项目,其界面上主要的控件及控件名称如下图所示:

图片

然后新建一个控制端项目,其界面上主要的控件及控件名称如下图所示:


图片

1、界面传输

首先来实现将客户端的界面传送至控制端,这个过程主要包括两个部分:在客户端传输本机界面至控制端、在控制端接受传输的数据。具体来说,在客户端传输本机界面至控制端又分为获取界面图像、将图形转换成传输数据(如字节)、传输数据。同样,在控制端接受传输的数据在接受数据流后,将数据流转换成字节后还需要转换成图形。下面来分别介绍这五个关键点如何来实现:

1)获取界面图像

获取界面图像主要通过BitBlt()CreateDC()来实现,首先必须对这两个函数进行引用,如下:

【客户端】:

 [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]

        private static extern bool BitBlt(

         IntPtr hdcDest, //目标设备的句柄

         int nXDest, // 目标对象的左上角的X坐标

         int nYDest, // 目标对象的左上角的Y坐标

         int nWidth, // 目标对象的矩形的宽度

         int nHeight, // 目标对象的矩形的长度

         IntPtr hdcSrc, // 源设备的句柄

         int nXSrc, // 源对象的左上角的X坐标

         int nYSrc, // 源对象的左上角的X坐标

         System.Int32 dwRop // 光栅的操作值

         );

        [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]

        private static extern IntPtr CreateDC(

         string lpszDriver, // 驱动名称

         string lpszDevice, // 设备名称

         string lpszOutput, // 无用,可以设定位"NULL"

         IntPtr lpInitData // 任意的打印机数据

         );

然后定义一个获取屏幕的函数GetScreenImage(),其返回值为Bitmap,该函数代码如下:

【客户端】:

        private Bitmap GetScreenImage(Point point01, Point point02, bool full)

        {

            //创建显示器的DC

            IntPtr dc1 = CreateDC("DISPLAY", null, null, (IntPtr)null);

            //由一个指定设备的句柄创建一个新的Graphics对象

            Graphics g1 = Graphics.FromHdc(dc1);

            Bitmap MyImage;

            int width, height;

            if (full)

            {

                width = Screen.PrimaryScreen.Bounds.Width;

                height = Screen.PrimaryScreen.Bounds.Height;

            }

            else

            {

                width = point02.X - point01.X;

                height = point02.Y - point01.Y;

            }

 

            //根据指定的宽度和高度创建一个与之相同大小的Bitmap对象

            MyImage = new Bitmap(width, height, g1);

 

            //获得屏幕的句柄

            Graphics g2 = Graphics.FromImage(MyImage);

            //获得位图的句柄

            IntPtr dc3 = g1.GetHdc();

            //把当前屏幕捕获到位图对象中

            IntPtr dc2 = g2.GetHdc();

            //把当前屏幕拷贝到位图中

            BitBlt(dc2, 0, 0, width, height, dc3, point01.X, point01.Y, 13369376);

            //释放屏幕句柄

            g1.ReleaseHdc(dc3);

            //释放位图句柄

            g2.ReleaseHdc(dc2);

            return MyImage;

        }

2)转换图像至字节

转换图像为字节可以采用MemoryStream类来实现,通过该类将图像读入内存流中,然后使用该类的ToArray()方法将数据流转换成字节数组,如下代码:

                Point point01 = new Point(), point02 = new Point();

                Bitmap bitmap = GetScreenImage(point01, point02, true);               

                MemoryStream memoryStream = new MemoryStream();                bitmap.Save(memoryStream,System.Drawing.Imaging.ImageFormat.Bmp);

                byte[] bytes = memoryStream.ToArray();

3)发送字节至控制端

发送数据主要还是采用TcpClient类来实现,通过TcpClient类连接控制端,如果连接成功则将图像转换成字节数据,并发送出去。如下代码:

【客户端】:

        private void SendImage()

        {

            TcpClient client = new TcpClient();

            Int32 port = Int32.Parse(portTextBox.Text);

            client.Connect(IPAddress.Parse(IPAddressTextBox.Text), port);

            if (client.Connected)

            {

                Point point01 = new Point(), point02 = new Point();

                Bitmap bitmap = GetScreenImage(point01, point02, true);               

                MemoryStream memoryStream = new MemoryStream();

                bitmap.Save(memoryStream,System.Drawing.Imaging.ImageFormat.Bmp);

                byte[] bytes = memoryStream.ToArray();

                NetworkStream stream = client.GetStream();

                stream.Write(bytes, 0, bytes.Length);

                stream.Close();

                client.Close();

            }

        }

在需要发送本机界面至控制端上,只需要调用SendImage()函数即可。

4将字节转换成图形

这个过程是在控制端获得客户端发送的数据后,通过接收的数据转换成图形。同样是采用MemoryStream类将字节数组读入内存流,然后使用Image类的FromStream()方法将数据流转换成图像,如下代码:

                        MemoryStream memoryStream = new MemoryStream();

                        byte[] bytes = new byte[1024];

                        int i;

                        while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)

                        {

                            memoryStream.Write(bytes, 0, i);

                        }

                        Image image = Image.FromStream(memoryStream);

其中,stream是获取的网络数据流,即接收的客户端传输的数据。

5)控制端接收数据

在控制端接收数据仍然采用TcpListener类来监听客户端发送的数据,如果有数据传输过来,就将其转换成图像。所以首先要在全局中定义TcpListener类,如下:

【控制端】:

TcpListener tcpListener;

然后定义监听函数用于监听客户端发送的数据,如下:

【控制端】:

        private void Listen()

        {

            try

            {

                Int32 port = Int32.Parse(portTextBox.Text);

                tcpListener = new TcpListener(port);

                tcpListener.Start();

                while (true)

                {

                    TcpClient client = tcpListener.AcceptTcpClient();

                    NetworkStream stream = client.GetStream();

                    if (stream.CanRead)

                    {

                        System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;

                        MemoryStream memoryStream = new MemoryStream();

                        byte[] bytes = new byte[1024];

                        int i;

                        while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)

                        {

                            memoryStream.Write(bytes, 0, i);

                        }

                        Image image = Image.FromStream(memoryStream);

                        ClientPictureBox.Image= image;

                        memoryStream.Close(); 

                    }

                    client.Close();

                }

            }

            finally

            {

                tcpListener.Stop();

            }

        }

在控制端用一个PictureBox控件(设置其Name属性为ClientPictureBox)来显示从客户端返回的界面,运行程序,其结果如下图所示:

图片

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
程序架构: WinForm .net 4.0 功能点: 一、日常提示 上下线提示,更新获取局域网QXin用户列表,正在输入提示、类QQ界面模式 二、字符串通信 单用户字符串通信、多用户字符串广播 三、文件通信 单用户单文件传送,单文件夹传送、多文件多文件夹混合传送。 多用户广播传送 程序实现过程: UDP通信:(上下线提示,字符串通信) 一发一回的方式,例如:用户A上线,以广播的方式发送“我上线啦”的消息,其他用户接收后把该用户加添到用户列表里,返回一个“已收到”信息,用户A接收到各个用户返回的信息并一一加载到用户列表。 TCP通信:(文件传送) 首先用户A以UDP方式通知用户B,”我要发送某某文件”,用户B接收后,AB用户开始进行TCP连接,然后发送文件 单文件发送和文件夹发送差别很大,由于文件夹不是文件,只能通过发送消息通知远程用户在什么地方建立一个文件夹,然后送该文件夹下的文件。如果该文件夹有子文件夹,又系同样的方式通知远程用户在哪个文件里新建子文件夹,不断递归。 (PS:飞鸽协议是开源的,不过飞秋可不是,飞秋虽然同样采用飞鸽协议,但是在此基础上增加修改了不少内容,要兼容飞秋需要用WPE抓包分析飞秋的数据包。) 分层架构模式思想: 所谓分层架构,分层架构并不是一个程序分几个模块或者源文件就是分层架构,分层架构是一种模式,分层架构必须只能自上往下操作,下层不知上层的内容,上层只能调用其下层的函数,UI层调用BLL层,BLL层调用DAL层. 而BLL层是绝不可以调用UI层的. 例如BLL层绝不能出现MessageBox等winform方法。而且,要做到BLL和DAl 在脱离UI表面层后,转到控制台通过调用其类和方法也能正常运行,才算好的分层架构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值