日期:2014-05-18  浏览次数:20872 次

用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