用C#做远程监控程序
用C#做远程监控程序
2009年12月05日
最近在做的C/S程序要加入远程监控的功能,于是去搜索怎么用C#来做这个功能,然后看了一些资料。最后有了一点点思路,远程监控其实就是总结出来一个大概的流程:
首先,实时的将被监控端的屏幕截图并发送到监控端。
然后,把本地的鼠标和键盘事件的值传到远程,然后再远程模拟出来。
有了想法那就开始做吧,先做第一步
一、屏幕截图并发送到服务器端
先要让客户端连接到服务器端,用的是TCP连接
程序代码
socket = new TcpClient(serveraddress, serverport);
ns = clientsocket.GetStream();
然后启动一个线程来截图,截图的代码可以看 C#截图代码。 可以在连接服务器之后就启动这个线程,我现在的是让服务器发一个命令到客户端,然后客户端再用一个线程来不断侦听服务器发来的消息,如果收到截图的命令,那么再启动截图。
截下的图片保存在内存流中,要注意的一点是,在调用了SAVE方法之后要重新设置流的位置为0
程序代码
MemoryStream ms = new MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
//将图片写入流,但是流的当前位置会改变(在流的末端)
ms.Position = 0;
//在调用ms.Read方法之前重设流的当前位置
截图已经完成,接下来就是要传送图片了。一次发送完整个图片是不好的,所以我们要把它分块传输。我设置了1024字节的缓冲区,循环发送数据。
程序代码
while (sendCount
程序代码
Byte[] buffer = new Byte[1024];
int count = socket.Receive(buffer);
while (count != 0)
{
if (count == 4)
break;
try
{
ms.Write(buffer, 0, count); //写入内存流
buffer = new Byte[1024];
Byte[] tempbuff = new Byte[1024];
count = socket.Receive(tempbuff);
buffer = tempbuff;
}
catch (Exception ex)
{ }
}
将内存流再转换为图片,然后显示出来,我用的是PictureBox,下面是显示图片的代码
程序代码
Image image = Image.FromStream(ms);
picScreen.Image = image;
ms.Flush();
ms = new MemoryStream();
到这里基本上就实现了第一步的功能,可以看到客户端的桌面了,小小的高兴一下~~~~不过还有一些问题,显示的速度慢,正在想办法解决这个问题。图片应该要压缩下,也许不传整张图片也是一个比较好的办法。
远程监控的第一步完成了,已经可以看见对方的桌面了。现在开始实现第二步,即远程控制部分。把本地的鼠标事件传到远程,在远程模拟鼠标事件,这部分参考了一些网上的源码。
要把鼠标类型(单击、双击、移动)和坐标转换成二进制然后发送到远程,这里定义一个鼠标事件的类,里面还需要有一个将接收到的字节转换成类型和坐标的函数,部分代码如下
程序代码
public class MouseHook
{
private Byte[] mouseType;
private Byte[] x;
private Byte[] y;
public MouseHook(MouseEventType mouseType, int x, int y)
{
this.mouseType = BitConverter.GetBytes((int)mouseType);
this.x = BitConverter.GetBytes(x);
this.y = BitConverter.GetBytes(y);
}
}
然后再定义鼠标类型的枚举,好区别不同的鼠标类型。
程序代码
public enum MouseEventType
{
MouseMove,
....
MouseClick,
}
在被控端要引入WIN32的API以模拟鼠标事件,用到的是user32.dll
程序代码
// 模拟鼠标事件的函数模型
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern void mouse_event(int flags, int dx, int dy, int dwData, int dwExtraInfo);
/// 设置光标到指定位置的函数模型
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool SetCursorPos(int X, int Y);
在服务器端显示图片用的是Picturebox控件,为了要实现控制,得在Picturebox添加几个事件MouseMove,MouseUp,MouseClick等事件,在这些事件触发的时候发送鼠标的类型和坐标。
这是其中的一个事件,鼠标单击事件
程序代码
private void picScreen_MouseClick(object sender, MouseEventArgs e)
{
MouseHook MouseEvent = new MouseHook(MouseEventType.MouseClick, e.X, e.Y);
ns.Write(MouseEvent.ToBytes(),0,12);
}
成功发送出去之后就可以在另一端接收了,接收到之后再转换为坐标,判断接收到的类型,模拟出相应的事件。需要定义委托来模拟鼠标事件。
程序代码
public delegate void DoMouseButtons(MouseEventFlag flags, int dx, int dy, int dwData, int dwExtraInfo);
private event DoMouseButtons MouseButton;
直接像下面这样使用就可以了
程序代码
MouseButton(MouseEventFlag.LeftDown, MEvent.X, MEvent.Y, 0, 0);
接收的代码我就懒得写出来了,其实就是和接收图片一样的。
到这里基本上控件的代码也完成了,测试了一下,可以控制了,但是会一卡一卡的,反应有点慢。写得有点乱,远程监控大概的流程就是这样。完成的代码还是很粗糙,也还有一些问题,需要做一些改进。
前面也说过,要实现键盘控制就是要在服务器端响应键盘事件,传送到客户端,客户端再模拟出来。
为了避免鼠标和键盘的事件传送的时候发生冲突,需要在客户端再连接一个不同的端口,服务端启动的时候监听这两个端口。具
体的代码可以参考第一篇里所写的。
定义一个键盘事件类型的枚举,主要就是按键按下和释放。
程序代码
public enum